diff options
author | Ermal Luçi <eri@FreeBSD.org> | 2017-02-10 05:16:14 +0000 |
---|---|---|
committer | Ermal Luçi <eri@FreeBSD.org> | 2017-02-10 05:16:14 +0000 |
commit | ed55edceef6ae6afec1878287d3c5d9f20cbf1fa (patch) | |
tree | 815a9f351acb302042eda4117868e6b1a44e391e /sys/netinet/udp_usrreq.c | |
parent | 281e4f2dd48e1a9b55f9d120227b6638bedea50e (diff) | |
download | src-ed55edceef6ae6afec1878287d3c5d9f20cbf1fa.tar.gz src-ed55edceef6ae6afec1878287d3c5d9f20cbf1fa.zip |
The patch provides the same socket option as Linux IP_ORIGDSTADDR.
Unfortunately they will have different integer value due to Linux value being already assigned in FreeBSD.
The patch is similar to IP_RECVDSTADDR but also provides the destination port value to the application.
This allows/improves implementation of transparent proxies on UDP sockets due to having the whole information on forwarded packets.
Sponsored-by: rsync.net
Differential Revision: D9235
Reviewed-by: adrian
Notes
Notes:
svn path=/head/; revision=313524
Diffstat (limited to 'sys/netinet/udp_usrreq.c')
-rw-r--r-- | sys/netinet/udp_usrreq.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index f24499dbd7f3..56da929ef827 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -304,7 +304,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, { struct sockaddr *append_sa; struct socket *so; - struct mbuf *opts = NULL; + struct mbuf *tmpopts, *opts = NULL; #ifdef INET6 struct sockaddr_in6 udp_in6; #endif @@ -319,7 +319,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, if (up->u_tun_func != NULL) { in_pcbref(inp); INP_RUNLOCK(inp); - (*up->u_tun_func)(n, off, inp, (struct sockaddr *)udp_in, + (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&udp_in[0], up->u_tun_ctx); INP_RLOCK(inp); return (in_pcbrele_rlocked(inp)); @@ -355,16 +355,27 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, #endif /* INET6 */ ip_savecontrol(inp, &opts, ip, n); } + if (inp->inp_vflag & INP_IPV4 && inp->inp_flags2 & INP_ORIGDSTADDR) { + tmpopts = sbcreatecontrol((caddr_t)&udp_in[1], + sizeof(struct sockaddr_in), IP_ORIGDSTADDR, IPPROTO_IP); + if (tmpopts) { + if (opts) { + tmpopts->m_next = opts; + opts = tmpopts; + } else + opts = tmpopts; + } + } #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { bzero(&udp_in6, sizeof(udp_in6)); udp_in6.sin6_len = sizeof(udp_in6); udp_in6.sin6_family = AF_INET6; - in6_sin_2_v4mapsin6(udp_in, &udp_in6); + in6_sin_2_v4mapsin6(&udp_in[0], &udp_in6); append_sa = (struct sockaddr *)&udp_in6; } else #endif /* INET6 */ - append_sa = (struct sockaddr *)udp_in; + append_sa = (struct sockaddr *)&udp_in[0]; m_adj(n, off); so = inp->inp_socket; @@ -390,7 +401,7 @@ udp_input(struct mbuf **mp, int *offp, int proto) uint16_t len, ip_len; struct inpcbinfo *pcbinfo; struct ip save_ip; - struct sockaddr_in udp_in; + struct sockaddr_in udpin[2]; struct mbuf *m; struct m_tag *fwd_tag; int cscov_partial, iphlen; @@ -435,11 +446,16 @@ udp_input(struct mbuf **mp, int *offp, int proto) * Construct sockaddr format source address. Stuff source address * and datagram in user buffer. */ - bzero(&udp_in, sizeof(udp_in)); - udp_in.sin_len = sizeof(udp_in); - udp_in.sin_family = AF_INET; - udp_in.sin_port = uh->uh_sport; - udp_in.sin_addr = ip->ip_src; + bzero(&udpin[0], sizeof(struct sockaddr_in)); + udpin[0].sin_len = sizeof(struct sockaddr_in); + udpin[0].sin_family = AF_INET; + udpin[0].sin_port = uh->uh_sport; + udpin[0].sin_addr = ip->ip_src; + bzero(&udpin[1], sizeof(struct sockaddr_in)); + udpin[1].sin_len = sizeof(struct sockaddr_in); + udpin[1].sin_family = AF_INET; + udpin[1].sin_port = uh->uh_dport; + udpin[1].sin_addr = ip->ip_dst; /* * Make mbuf data length reflect UDP length. If not enough data to @@ -568,7 +584,7 @@ udp_input(struct mbuf **mp, int *offp, int proto) blocked = imo_multi_filter(imo, ifp, (struct sockaddr *)&group, - (struct sockaddr *)&udp_in); + (struct sockaddr *)&udpin[0]); if (blocked != MCAST_PASS) { if (blocked == MCAST_NOTGMEMBER) IPSTAT_INC(ips_notmember); @@ -587,7 +603,7 @@ udp_input(struct mbuf **mp, int *offp, int proto) UDP_PROBE(receive, NULL, last, ip, last, uh); if (udp_append(last, ip, n, iphlen, - &udp_in)) { + udpin)) { goto inp_lost; } } @@ -620,7 +636,7 @@ udp_input(struct mbuf **mp, int *offp, int proto) goto badunlocked; } UDP_PROBE(receive, NULL, last, ip, last, uh); - if (udp_append(last, ip, m, iphlen, &udp_in) == 0) + if (udp_append(last, ip, m, iphlen, udp_in) == 0) INP_RUNLOCK(last); inp_lost: INP_INFO_RUNLOCK(pcbinfo); @@ -710,7 +726,7 @@ udp_input(struct mbuf **mp, int *offp, int proto) } UDP_PROBE(receive, NULL, inp, ip, inp, uh); - if (udp_append(inp, ip, m, iphlen, &udp_in) == 0) + if (udp_append(inp, ip, m, iphlen, udp_in) == 0) INP_RUNLOCK(inp); return (IPPROTO_DONE); |