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. Reviewed by: adrian, aw Approved by: ae (mentor) Sponsored by: rsync.net Differential Revision: D9235
This commit is contained in:
parent
82bdb13eb8
commit
f2a480c25c
@ -136,6 +136,37 @@ determined by the destination address, returns an
|
||||
error.
|
||||
.Pp
|
||||
If the
|
||||
.Dv IP_ORIGDSTADDR
|
||||
option is enabled on a
|
||||
.Dv SOCK_DGRAM
|
||||
socket,
|
||||
the
|
||||
.Xr recvmsg 2
|
||||
call will return the destination
|
||||
.Tn IP
|
||||
address and destination port or a
|
||||
.Tn UDP
|
||||
datagram.
|
||||
The
|
||||
.Vt msg_control
|
||||
field in the
|
||||
.Vt msghdr
|
||||
structure points to a buffer
|
||||
that contains a
|
||||
.Vt cmsghdr
|
||||
structure followed by the
|
||||
.Tn in_sockkaddr
|
||||
structre.
|
||||
The
|
||||
.Vt cmsghdr
|
||||
fields have the following values:
|
||||
.Bd -literal
|
||||
cmsg_len = CMSG_LEN(sizeof(struct in_sockaddr))
|
||||
cmsg_level = IPPROTO_IP
|
||||
cmsg_type = IP_ORIGDSTADDR
|
||||
.Ed
|
||||
.Pp
|
||||
If the
|
||||
.Dv IP_RECVDSTADDR
|
||||
option is enabled on a
|
||||
.Dv SOCK_DGRAM
|
||||
|
@ -156,6 +156,9 @@ datagrams sent on this socket.
|
||||
.\" .It Dv IPV6_RECVDSTADDR Fa "int *"
|
||||
.\" Get or set the status of whether datagrams are received with
|
||||
.\" destination addresses.
|
||||
.\" .It Dv IPV6_ORIGDSTADDR Fa "int *"
|
||||
.\" Get or set the status of whether datagrams are received with
|
||||
.\" destination addresses and destination ports.
|
||||
.\" .It Dv IPV6_RETOPTS
|
||||
.\" Get or set IPv6 options.
|
||||
.It Dv IPV6_MULTICAST_IF Fa "u_int *"
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -618,6 +618,7 @@ short inp_so_options(const struct inpcb *inp);
|
||||
#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.
|
||||
|
@ -1065,6 +1065,7 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
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 sockopt *sopt)
|
||||
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 sockopt *sopt)
|
||||
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 sockopt *sopt)
|
||||
optval = OPTBIT(INP_RECVDSTADDR);
|
||||
break;
|
||||
|
||||
case IP_ORIGDSTADDR:
|
||||
optval = OPTBIT2(INP_ORIGDSTADDR);
|
||||
break;
|
||||
|
||||
case IP_RECVTTL:
|
||||
optval = OPTBIT(INP_RECVTTL);
|
||||
break;
|
||||
|
@ -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 udp_in[2];
|
||||
struct mbuf *m;
|
||||
struct m_tag *fwd_tag;
|
||||
int cscov_partial, iphlen;
|
||||
@ -435,11 +446,15 @@ 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(&udp_in[0], sizeof(struct sockaddr_in) * 2);
|
||||
udp_in[0].sin_len = sizeof(struct sockaddr_in);
|
||||
udp_in[0].sin_family = AF_INET;
|
||||
udp_in[0].sin_port = uh->uh_sport;
|
||||
udp_in[0].sin_addr = ip->ip_src;
|
||||
udp_in[1].sin_len = sizeof(struct sockaddr_in);
|
||||
udp_in[1].sin_family = AF_INET;
|
||||
udp_in[1].sin_port = uh->uh_dport;
|
||||
udp_in[1].sin_addr = ip->ip_dst;
|
||||
|
||||
/*
|
||||
* Make mbuf data length reflect UDP length. If not enough data to
|
||||
@ -568,7 +583,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 *)&udp_in[0]);
|
||||
if (blocked != MCAST_PASS) {
|
||||
if (blocked == MCAST_NOTGMEMBER)
|
||||
IPSTAT_INC(ips_notmember);
|
||||
@ -587,7 +602,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)) {
|
||||
udp_in)) {
|
||||
goto inp_lost;
|
||||
}
|
||||
}
|
||||
@ -620,7 +635,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 +725,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);
|
||||
|
||||
|
@ -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 72 /* 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.
|
||||
|
@ -1267,7 +1267,7 @@ in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
|
||||
}
|
||||
|
||||
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, struct mbuf *m)
|
||||
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... */
|
||||
|
||||
|
@ -113,7 +113,7 @@ int in6_mapped_sockaddr(struct socket *so, struct sockaddr **nam);
|
||||
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_ */
|
||||
|
@ -1545,6 +1545,7 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
|
||||
#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;
|
||||
|
@ -166,7 +166,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
|
||||
|
||||
RIP6STAT_INC(rip6s_ipackets);
|
||||
|
||||
init_sin6(&fromsa, m); /* general init */
|
||||
init_sin6(&fromsa, m, 0); /* general init */
|
||||
|
||||
ifp = m->m_pkthdr.rcvif;
|
||||
|
||||
|
@ -137,7 +137,7 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
|
||||
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 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 *)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 mbuf *n, int off,
|
||||
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), IPV6_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 proto)
|
||||
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, int proto)
|
||||
/*
|
||||
* 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, int proto)
|
||||
|
||||
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, int proto)
|
||||
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, int proto)
|
||||
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, int proto)
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user