summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorvgross <vgross@openbsd.org>2016-08-16 22:21:17 +0000
committervgross <vgross@openbsd.org>2016-08-16 22:21:17 +0000
commitfdc836786e82a355da43a67a64b447a9dced2df7 (patch)
treeacba4ba212bdec12ab9b475bdc5e207e8dd2f3e3 /sys/netinet
parentTrack SSID in leases file and only consider leases from the current SSID when (diff)
downloadwireguard-openbsd-fdc836786e82a355da43a67a64b447a9dced2df7.tar.xz
wireguard-openbsd-fdc836786e82a355da43a67a64b447a9dced2df7.zip
Add IP_SENDSRCADDR cmsg for UDP sockets. As suggested by sthen@,
IP_SENDSRCADDR == IP_RECVDSTADDR. OK sthen@ jca@ bluhm@
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in.h4
-rw-r--r--sys/netinet/udp_usrreq.c31
2 files changed, 31 insertions, 4 deletions
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 31b2a26b453..a390574da3a 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.117 2016/06/28 17:18:24 chris Exp $ */
+/* $OpenBSD: in.h,v 1.118 2016/08/16 22:21:17 vgross Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -307,6 +307,8 @@ struct ip_opts {
#define IP_RECVRTABLE 35 /* bool; receive rdomain w/dgram */
#define IP_IPSECFLOWINFO 36 /* bool; IPsec flow info for dgram */
#define IP_IPDEFTTL 37 /* int; IP TTL system default */
+#define IP_SENDSRCADDR IP_RECVDSTADDR /* struct in_addr; */
+ /* source address to use */
#define IP_RTABLE 0x1021 /* int; routing table, see SO_RTABLE */
#define IP_DIVERTFL 0x1022 /* int; divert direction flag opt */
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 6e2589ea607..01b6c5b64ef 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.217 2016/08/04 20:46:24 vgross Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.218 2016/08/16 22:21:17 vgross Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -909,6 +909,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr,
struct sockaddr_in *sin = NULL;
struct udpiphdr *ui;
u_int32_t ipsecflowinfo = 0;
+ struct sockaddr_in src_sin;
int len = m->m_pkthdr.len;
struct in_addr *laddr;
int error = 0;
@@ -927,6 +928,8 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr,
goto release;
}
+ memset(&src_sin, 0, sizeof(src_sin));
+
if (control) {
u_int clen;
struct cmsghdr *cm;
@@ -960,9 +963,20 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr,
cm->cmsg_level == IPPROTO_IP &&
cm->cmsg_type == IP_IPSECFLOWINFO) {
ipsecflowinfo = *(u_int32_t *)CMSG_DATA(cm);
- break;
- }
+ } else
#endif
+ if (cm->cmsg_len == CMSG_LEN(sizeof(struct in_addr)) &&
+ cm->cmsg_level == IPPROTO_IP &&
+ cm->cmsg_type == IP_SENDSRCADDR) {
+ memcpy(&src_sin.sin_addr, CMSG_DATA(cm),
+ sizeof(struct in_addr));
+ src_sin.sin_family = AF_INET;
+ src_sin.sin_len = sizeof(src_sin);
+ /* no check on reuse when sin->sin_port == 0 */
+ if ((error = in_pcbaddrisavail(inp, &src_sin,
+ 0, curproc)))
+ goto release;
+ }
clen -= CMSG_ALIGN(cm->cmsg_len);
cmsgs += CMSG_ALIGN(cm->cmsg_len);
} while (clen);
@@ -1000,6 +1014,17 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr,
if (error)
goto release;
}
+
+ if (src_sin.sin_len > 0 &&
+ src_sin.sin_addr.s_addr != INADDR_ANY &&
+ src_sin.sin_addr.s_addr != inp->inp_laddr.s_addr) {
+ src_sin.sin_port = inp->inp_lport;
+ if (inp->inp_laddr.s_addr != INADDR_ANY &&
+ (error =
+ in_pcbaddrisavail(inp, &src_sin, 0, curproc)))
+ goto release;
+ laddr = &src_sin.sin_addr;
+ }
} else {
if (inp->inp_faddr.s_addr == INADDR_ANY) {
error = ENOTCONN;