Author: eri
Date: Fri Feb 10 05:16:14 2017
New Revision: 313524
URL: https://svnweb.freebsd.org/changeset/base/313524

Log:
  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

Modified:
  head/sys/netinet/in.h
  head/sys/netinet/in_pcb.c
  head/sys/netinet/in_pcb.h
  head/sys/netinet/ip_output.c
  head/sys/netinet/udp_usrreq.c
  head/sys/netinet6/in6.h
  head/sys/netinet6/in6_pcb.c
  head/sys/netinet6/in6_pcb.h
  head/sys/netinet6/ip6_output.c
  head/sys/netinet6/raw_ip6.c
  head/sys/netinet6/udp6_usrreq.c

Modified: head/sys/netinet/in.h
==============================================================================
--- head/sys/netinet/in.h       Fri Feb 10 05:14:19 2017        (r313523)
+++ head/sys/netinet/in.h       Fri Feb 10 05:16:14 2017        (r313524)
@@ -433,6 +433,8 @@ __END_DECLS
 #define        IP_BINDANY              24   /* bool: allow bind to any address 
*/
 #define        IP_BINDMULTI            25   /* bool: allow multiple listeners 
on a tuple */
 #define        IP_RSS_LISTEN_BUCKET    26   /* int; set RSS listen bucket */
+#define        IP_ORIGDSTADDR          27   /* bool: receive IP dst addr/port 
w/dgram */
+#define        IP_RECVORIGDSTADDR      IP_ORIGDSTADDR
 
 /*
  * Options for controlling the firewall and dummynet.

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c   Fri Feb 10 05:14:19 2017        (r313523)
+++ head/sys/netinet/in_pcb.c   Fri Feb 10 05:16:14 2017        (r313524)
@@ -2492,6 +2492,10 @@ db_print_inpflags(int inp_flags)
                db_printf("%sINP_RECVDSTADDR", comma ? ", " : "");
                comma = 1;
        }
+       if (inp_flags & INP_ORIGDSTADDR) {
+               db_printf("%sINP_ORIGDSTADDR", comma ? ", " : "");
+               comma = 1;
+       }
        if (inp_flags & INP_HDRINCL) {
                db_printf("%sINP_HDRINCL", comma ? ", " : "");
                comma = 1;

Modified: head/sys/netinet/in_pcb.h
==============================================================================
--- head/sys/netinet/in_pcb.h   Fri Feb 10 05:14:19 2017        (r313523)
+++ head/sys/netinet/in_pcb.h   Fri Feb 10 05:16:14 2017        (r313524)
@@ -618,6 +618,7 @@ short       inp_so_options(const struct inpcb 
 #define        INP_RECVFLOWID          0x00000100 /* populate recv datagram 
with flow info */
 #define        INP_RECVRSSBUCKETID     0x00000200 /* populate recv datagram 
with bucket id */
 #define        INP_RATE_LIMIT_CHANGED  0x00000400 /* rate limit needs 
attention */
+#define        INP_ORIGDSTADDR         0x00000800 /* receive IP dst 
address/port */
 
 /*
  * Flags passed to in_pcblookup*() functions.

Modified: head/sys/netinet/ip_output.c
==============================================================================
--- head/sys/netinet/ip_output.c        Fri Feb 10 05:14:19 2017        
(r313523)
+++ head/sys/netinet/ip_output.c        Fri Feb 10 05:16:14 2017        
(r313524)
@@ -1065,6 +1065,7 @@ ip_ctloutput(struct socket *so, struct s
                case IP_MINTTL:
                case IP_RECVOPTS:
                case IP_RECVRETOPTS:
+               case IP_ORIGDSTADDR:
                case IP_RECVDSTADDR:
                case IP_RECVTTL:
                case IP_RECVIF:
@@ -1126,6 +1127,10 @@ ip_ctloutput(struct socket *so, struct s
                                OPTSET(INP_RECVDSTADDR);
                                break;
 
+                       case IP_ORIGDSTADDR:
+                               OPTSET2(INP_ORIGDSTADDR, optval);
+                               break;
+
                        case IP_RECVTTL:
                                OPTSET(INP_RECVTTL);
                                break;
@@ -1258,6 +1263,7 @@ ip_ctloutput(struct socket *so, struct s
                case IP_MINTTL:
                case IP_RECVOPTS:
                case IP_RECVRETOPTS:
+               case IP_ORIGDSTADDR:
                case IP_RECVDSTADDR:
                case IP_RECVTTL:
                case IP_RECVIF:
@@ -1303,6 +1309,10 @@ ip_ctloutput(struct socket *so, struct s
                                optval = OPTBIT(INP_RECVDSTADDR);
                                break;
 
+                       case IP_ORIGDSTADDR:
+                               optval = OPTBIT2(INP_ORIGDSTADDR);
+                               break;
+
                        case IP_RECVTTL:
                                optval = OPTBIT(INP_RECVTTL);
                                break;

Modified: head/sys/netinet/udp_usrreq.c
==============================================================================
--- head/sys/netinet/udp_usrreq.c       Fri Feb 10 05:14:19 2017        
(r313523)
+++ head/sys/netinet/udp_usrreq.c       Fri Feb 10 05:16:14 2017        
(r313524)
@@ -304,7 +304,7 @@ udp_append(struct inpcb *inp, struct ip 
 {
        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 
        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 
 #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, i
        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, i
         * 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, i
 
                                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, i
                                        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, i
                        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, i
        }
 
        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);
 

Modified: head/sys/netinet6/in6.h
==============================================================================
--- head/sys/netinet6/in6.h     Fri Feb 10 05:14:19 2017        (r313523)
+++ head/sys/netinet6/in6.h     Fri Feb 10 05:16:14 2017        (r313524)
@@ -497,6 +497,9 @@ struct route_in6 {
 #define        IPV6_RECVFLOWID         70 /* bool; receive IP6 flowid/flowtype 
w/ datagram */
 #define        IPV6_RECVRSSBUCKETID    71 /* bool; receive IP6 RSS bucket id 
w/ datagram */
 
+#define        IPV6_ORIGDSTADDR        65 /* bool: allow getting dstaddr /port 
info */
+#define        IPV6_RECVORIGDSTADDR    IPV6_ORIGDSTADDR
+
 /*
  * The following option is private; do not use it from user applications.
  * It is deliberately defined to the same value as IP_MSFILTER.

Modified: head/sys/netinet6/in6_pcb.c
==============================================================================
--- head/sys/netinet6/in6_pcb.c Fri Feb 10 05:14:19 2017        (r313523)
+++ head/sys/netinet6/in6_pcb.c Fri Feb 10 05:16:14 2017        (r313524)
@@ -1267,7 +1267,7 @@ in6_pcblookup_mbuf(struct inpcbinfo *pcb
 }
 
 void
-init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m)
+init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m, int srcordst)
 {
        struct ip6_hdr *ip;
 
@@ -1275,7 +1275,7 @@ init_sin6(struct sockaddr_in6 *sin6, str
        bzero(sin6, sizeof(*sin6));
        sin6->sin6_len = sizeof(*sin6);
        sin6->sin6_family = AF_INET6;
-       sin6->sin6_addr = ip->ip6_src;
+       sin6->sin6_addr = srcordst ? ip->ip6_dst : ip->ip6_src;
 
        (void)sa6_recoverscope(sin6); /* XXX: should catch errors... */
 

Modified: head/sys/netinet6/in6_pcb.h
==============================================================================
--- head/sys/netinet6/in6_pcb.h Fri Feb 10 05:14:19 2017        (r313523)
+++ head/sys/netinet6/in6_pcb.h Fri Feb 10 05:16:14 2017        (r313524)
@@ -113,7 +113,7 @@ int in6_mapped_sockaddr(struct socket *s
 int    in6_mapped_peeraddr(struct socket *so, struct sockaddr **nam);
 int    in6_selecthlim(struct in6pcb *, struct ifnet *);
 int    in6_pcbsetport(struct in6_addr *, struct inpcb *, struct ucred *);
-void   init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m);
+void   init_sin6(struct sockaddr_in6 *sin6, struct mbuf *m, int);
 #endif /* _KERNEL */
 
 #endif /* !_NETINET6_IN6_PCB_H_ */

Modified: head/sys/netinet6/ip6_output.c
==============================================================================
--- head/sys/netinet6/ip6_output.c      Fri Feb 10 05:14:19 2017        
(r313523)
+++ head/sys/netinet6/ip6_output.c      Fri Feb 10 05:16:14 2017        
(r313524)
@@ -1545,6 +1545,7 @@ ip6_ctloutput(struct socket *so, struct 
 #endif
                        case IPV6_V6ONLY:
                        case IPV6_AUTOFLOWLABEL:
+                       case IPV6_ORIGDSTADDR:
                        case IPV6_BINDANY:
                        case IPV6_BINDMULTI:
 #ifdef RSS
@@ -1730,6 +1731,9 @@ do { \
                                        OPTSET(IN6P_AUTOFLOWLABEL);
                                        break;
 
+                               case IPV6_ORIGDSTADDR:
+                                       OPTSET2(INP_ORIGDSTADDR, optval);
+                                       break;
                                case IPV6_BINDANY:
                                        OPTSET(INP_BINDANY);
                                        break;
@@ -2018,6 +2022,10 @@ do { \
                                        optval = OPTBIT(IN6P_AUTOFLOWLABEL);
                                        break;
 
+                               case IPV6_ORIGDSTADDR:
+                                       optval = OPTBIT2(INP_ORIGDSTADDR);
+                                       break;
+
                                case IPV6_BINDANY:
                                        optval = OPTBIT(INP_BINDANY);
                                        break;

Modified: head/sys/netinet6/raw_ip6.c
==============================================================================
--- head/sys/netinet6/raw_ip6.c Fri Feb 10 05:14:19 2017        (r313523)
+++ head/sys/netinet6/raw_ip6.c Fri Feb 10 05:16:14 2017        (r313524)
@@ -166,7 +166,7 @@ rip6_input(struct mbuf **mp, int *offp, 
 
        RIP6STAT_INC(rip6s_ipackets);
 
-       init_sin6(&fromsa, m); /* general init */
+       init_sin6(&fromsa, m, 0); /* general init */
 
        ifp = m->m_pkthdr.rcvif;
 

Modified: head/sys/netinet6/udp6_usrreq.c
==============================================================================
--- head/sys/netinet6/udp6_usrreq.c     Fri Feb 10 05:14:19 2017        
(r313523)
+++ head/sys/netinet6/udp6_usrreq.c     Fri Feb 10 05:16:14 2017        
(r313524)
@@ -137,7 +137,7 @@ udp6_append(struct inpcb *inp, struct mb
     struct sockaddr_in6 *fromsa)
 {
        struct socket *so;
-       struct mbuf *opts;
+       struct mbuf *opts = NULL, *tmp_opts;
        struct udpcb *up;
 
        INP_LOCK_ASSERT(inp);
@@ -149,7 +149,7 @@ udp6_append(struct inpcb *inp, struct mb
        if (up->u_tun_func != NULL) {
                in_pcbref(inp);
                INP_RUNLOCK(inp);
-               (*up->u_tun_func)(n, off, inp, (struct sockaddr *)fromsa,
+               (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&fromsa[0],
                    up->u_tun_ctx);
                INP_RLOCK(inp);
                return (in_pcbrele_rlocked(inp));
@@ -173,11 +173,23 @@ udp6_append(struct inpcb *inp, struct mb
        if (inp->inp_flags & INP_CONTROLOPTS ||
            inp->inp_socket->so_options & SO_TIMESTAMP)
                ip6_savecontrol(inp, n, &opts);
+       if (inp->inp_vflag & INP_IPV6 && inp->inp_flags2 & INP_ORIGDSTADDR) {
+               tmp_opts = sbcreatecontrol((caddr_t)&fromsa[1],
+                        sizeof(struct sockaddr_in6), IP_ORIGDSTADDR, 
IPPROTO_IPV6);
+                if (tmp_opts) {
+                        if (opts) {
+                                tmp_opts->m_next = opts;
+                                opts = tmp_opts;
+                        } else
+                                opts = tmp_opts;
+                }
+
+       }
        m_adj(n, off + sizeof(struct udphdr));
 
        so = inp->inp_socket;
        SOCKBUF_LOCK(&so->so_rcv);
-       if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n,
+       if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)&fromsa[0], n,
            opts) == 0) {
                SOCKBUF_UNLOCK(&so->so_rcv);
                m_freem(n);
@@ -202,7 +214,7 @@ udp6_input(struct mbuf **mp, int *offp, 
        int off = *offp;
        int cscov_partial;
        int plen, ulen;
-       struct sockaddr_in6 fromsa;
+       struct sockaddr_in6 fromsa[2];
        struct m_tag *fwd_tag;
        uint16_t uh_sum;
        uint8_t nxt;
@@ -277,8 +289,10 @@ udp6_input(struct mbuf **mp, int *offp, 
        /*
         * Construct sockaddr format source address.
         */
-       init_sin6(&fromsa, m);
-       fromsa.sin6_port = uh->uh_sport;
+       init_sin6(&fromsa[0], m, 0);
+       fromsa[0].sin6_port = uh->uh_sport;
+       init_sin6(&fromsa[1], m, 1);
+       fromsa[1].sin6_port = uh->uh_dport;
 
        pcbinfo = udp_get_inpcbinfo(nxt);
        if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
@@ -349,7 +363,7 @@ udp6_input(struct mbuf **mp, int *offp, 
 
                                blocked = im6o_mc_filter(imo, ifp,
                                        (struct sockaddr *)&mcaddr,
-                                       (struct sockaddr *)&fromsa);
+                                       (struct sockaddr *)&fromsa[0]);
                                if (blocked != MCAST_PASS) {
                                        if (blocked == MCAST_NOTGMEMBER)
                                                IP6STAT_INC(ip6s_notmember);
@@ -370,7 +384,7 @@ udp6_input(struct mbuf **mp, int *offp, 
                                        INP_RLOCK(last);
                                        UDP_PROBE(receive, NULL, last, ip6,
                                            last, uh);
-                                       if (udp6_append(last, n, off, &fromsa))
+                                       if (udp6_append(last, n, off, fromsa))
                                                goto inp_lost;
                                        INP_RUNLOCK(last);
                                }
@@ -402,7 +416,7 @@ udp6_input(struct mbuf **mp, int *offp, 
                INP_RLOCK(last);
                INP_INFO_RUNLOCK(pcbinfo);
                UDP_PROBE(receive, NULL, last, ip6, last, uh);
-               if (udp6_append(last, m, off, &fromsa) == 0) 
+               if (udp6_append(last, m, off, fromsa) == 0) 
                        INP_RUNLOCK(last);
        inp_lost:
                return (IPPROTO_DONE);
@@ -482,7 +496,7 @@ udp6_input(struct mbuf **mp, int *offp, 
                }
        }
        UDP_PROBE(receive, NULL, inp, ip6, inp, uh);
-       if (udp6_append(inp, m, off, &fromsa) == 0)
+       if (udp6_append(inp, m, off, fromsa) == 0)
                INP_RUNLOCK(inp);
        return (IPPROTO_DONE);
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to