diff -uNr ./xl2tpd-1.2.4.orig/call.c ./xl2tpd-1.2.4/call.c --- ./xl2tpd-1.2.4.orig/call.c 2009-03-09 08:25:30.000000000 +0900 +++ ./xl2tpd-1.2.4/call.c 2010-05-14 03:34:40.461125516 +0900 @@ -618,7 +618,7 @@ } struct call *get_call (int tunnel, int call, unsigned int addr, int port, - IPsecSAref_t refme, IPsecSAref_t refhim) + unsigned int localaddr, IPsecSAref_t refme, IPsecSAref_t refhim) { /* * Figure out which call struct should handle this. @@ -695,9 +695,11 @@ }; st->peer.sin_family = AF_INET; st->peer.sin_port = port; + st->local.sin_family = AF_INET; st->refme = refme; st->refhim = refhim; bcopy (&addr, &st->peer.sin_addr, sizeof (addr)); + bcopy (&localaddr, &st->local.sin_addr, sizeof (localaddr)); st->next = tunnels.head; tunnels.head = st; tunnels.count++; diff -uNr ./xl2tpd-1.2.4.orig/call.h ./xl2tpd-1.2.4/call.h --- ./xl2tpd-1.2.4.orig/call.h 2009-03-09 08:25:30.000000000 +0900 +++ ./xl2tpd-1.2.4/call.h 2010-05-14 03:34:52.625126441 +0900 @@ -98,7 +98,7 @@ extern void push_handler (int); extern void toss (struct buffer *); extern struct call *get_call (int tunnel, int call, unsigned int addr, - int port, + int port, unsigned int localaddr, IPsecSAref_t refme, IPsecSAref_t refhim); extern struct call *get_tunnel (int, unsigned int, int); extern void destroy_call (struct call *); diff -uNr ./xl2tpd-1.2.4.orig/l2tp.h ./xl2tpd-1.2.4/l2tp.h --- ./xl2tpd-1.2.4.orig/l2tp.h 2009-03-09 08:25:30.000000000 +0900 +++ ./xl2tpd-1.2.4/l2tp.h 2010-05-14 03:38:04.172126651 +0900 @@ -146,6 +146,7 @@ unsigned short port; /* Port on remote end */ #else struct sockaddr_in peer; /* Peer's Address */ + struct sockaddr_in local; /* Local's Address */ #endif int debug; /* Are we debugging or not? */ int nego; /* Show Negotiation? */ diff -uNr ./xl2tpd-1.2.4.orig/network.c ./xl2tpd-1.2.4/network.c --- ./xl2tpd-1.2.4.orig/network.c 2009-03-09 08:25:30.000000000 +0900 +++ ./xl2tpd-1.2.4/network.c 2010-05-14 04:03:15.057126011 +0900 @@ -77,6 +77,11 @@ gconfig.ipsecsaref=0; } + arg=1; + if (setsockopt(server_socket, IPPROTO_IP, IP_PKTINFO, &arg, sizeof(arg)) != 0) { + l2tp_log(LOG_CRIT, "setsockopt recvref[%d]: %s\n", IP_PKTINFO, strerror(errno)); + } + #else l2tp_log(LOG_INFO, "No attempt being made to use IPsec SAref's since we're not on a Linux machine.\n"); @@ -257,8 +262,8 @@ void udp_xmit (struct buffer *buf, struct tunnel *t) { - struct cmsghdr *cmsg; - char cbuf[CMSG_SPACE(sizeof (unsigned int))]; + struct cmsghdr *cmsg = NULL; + char cbuf[CMSG_SPACE(sizeof (unsigned int)) + CMSG_SPACE(sizeof(struct in_pktinfo))]; unsigned int *refp; struct msghdr msgh; int err; @@ -288,6 +293,28 @@ msgh.msg_controllen = cmsg->cmsg_len; } + + if (t->local.sin_addr.s_addr) { + if(gconfig.debug_network) { + l2tp_log(LOG_DEBUG,"sending with setting source address saref=%s\n", inet_ntoa(t->local.sin_addr)); + } + + struct in_pktinfo* ipi; + msgh.msg_controllen = sizeof(cbuf); + + cmsg = (cmsg ? CMSG_NXTHDR(&msgh, cmsg) : CMSG_FIRSTHDR(&msgh)); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + + ipi = (struct in_pktinfo*)CMSG_DATA(cmsg); + ipi->ipi_ifindex = 0; + ipi->ipi_addr.s_addr = 0; + bcopy(&t->local.sin_addr, &ipi->ipi_spec_dst, sizeof(ipi->ipi_spec_dst)); + + msgh.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); + } + iov.iov_base = buf->start; iov.iov_len = buf->len; @@ -388,6 +415,8 @@ struct iovec iov; char cbuf[256]; unsigned int refme, refhim; + struct cmsghdr *cmsg; + struct in_pktinfo* inpkt = NULL; /* This one buffer can be recycled for everything except control packets */ buf = new_buf (MAX_RECV_SIZE); @@ -478,7 +507,6 @@ /* extract IPsec info out */ if(gconfig.ipsecsaref) { - struct cmsghdr *cmsg; /* Process auxiliary received data in msgh */ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; @@ -494,6 +522,12 @@ } } + for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { + inpkt = (struct in_pktinfo*)CMSG_DATA(cmsg); + } + } + /* * some logic could be added here to verify that we only * get L2TP packets inside of IPsec, or to provide different @@ -517,7 +551,7 @@ } if (! (c = get_call (tunnel, call, from.sin_addr.s_addr, - from.sin_port, refme, refhim))) + from.sin_port, (inpkt ? inpkt->ipi_spec_dst.s_addr : 0), refme, refhim))) { if ((c = get_tunnel (tunnel, from.sin_addr.s_addr, diff -uNr ./xl2tpd-1.2.4.orig/xl2tpd.c ./xl2tpd-1.2.4/xl2tpd.c --- ./xl2tpd-1.2.4.orig/xl2tpd.c 2009-03-09 08:25:30.000000000 +0900 +++ ./xl2tpd-1.2.4/xl2tpd.c 2010-05-14 03:37:08.664125809 +0900 @@ -599,7 +599,7 @@ * to do IPsec properly here, we need to set a socket policy, * and/or communicate with pluto. */ - tmp = get_call (0, 0, addr, port, IPSEC_SAREF_NULL, IPSEC_SAREF_NULL); + tmp = get_call (0, 0, addr, port, 0, IPSEC_SAREF_NULL, IPSEC_SAREF_NULL); if (!tmp) { l2tp_log (LOG_WARNING, "%s: Unable to create tunnel to %s.\n", __FUNCTION__,