diff options
| author | christos <christos@NetBSD.org> | 2018-01-01 00:51:36 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2018-01-01 00:51:36 +0000 |
| commit | 8a09fa14a0d307ae1a3639ba5ffaa467976992da (patch) | |
| tree | 181cd544507c29ffa6c81a6311bbac8d0d885f62 | |
| parent | 8362fcc1d3142d17cdbbae38e1c2bd16f37d4c48 (diff) | |
1) "#define ipi_spec_dst ipi_addr" in <netinet/in.h>
2) Change the IP_RECVPKTINFO option to control the generation of
IP_PKTINFO control messages, the way it's done in Solaris.
3) Remove the superfluous IP_RECVPKTINFO control message.
4) Change the IP_PKTINFO option to do different things depending on
the parameter it's supplied with:
- If it's sizeof(int), assume it's being used as in Linux:
- If it's non-zero, turn on the IP_RECVPKTINFO option.
- If it's zero, turn off the IP_RECVPKTINFO option.
- If it's sizeof(struct in_pktinfo), assume it's being used as in
Solaris, to set a default for the source interface and/or
source address for outgoing packets on the socket.
5) Return what Linux or Solaris compatible code expects, depending
on data size, and just added a fallback to a Linux (and current NetBSD)
compatible value if the size is unknown (as it is now), or,
in the future, if the calling application specifies a receiving
buffer that doesn't match either data item.
From: Tom Ivar Helbekkmo
| -rw-r--r-- | share/man/man4/ip.4 | 61 | ||||
| -rw-r--r-- | sys/netinet/in.h | 10 | ||||
| -rw-r--r-- | sys/netinet/in_pcb.c | 5 | ||||
| -rw-r--r-- | sys/netinet/in_pcb.h | 9 | ||||
| -rw-r--r-- | sys/netinet/ip_input.c | 13 | ||||
| -rw-r--r-- | sys/netinet/ip_output.c | 110 | ||||
| -rw-r--r-- | sys/sys/param.h | 4 |
7 files changed, 157 insertions, 55 deletions
diff --git a/share/man/man4/ip.4 b/share/man/man4/ip.4 index b84a976b35b..27e506d805e 100644 --- a/share/man/man4/ip.4 +++ b/share/man/man4/ip.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: ip.4,v 1.40 2017/08/13 18:19:44 wiz Exp $ +.\" $NetBSD: ip.4,v 1.41 2018/01/01 00:51:36 christos Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)ip.4 8.2 (Berkeley) 11/30/93 .\" -.Dd August 10, 2017 +.Dd December 31, 2017 .Dt IP 4 .Os .Sh NAME @@ -96,8 +96,8 @@ setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, buf, ipsec_get_policylen(buf)); .Ed .Pp The -.Dv IP_PKTINFO -option can be used to turn on receiving of information about the source +.Dv IP_RECVPKTINFO +option can be used to turn on receiving of information about the destination address of the packet, and the interface index. The information is passed in a .Vt struct in_pktinfo @@ -117,13 +117,24 @@ cmsg_type = IP_PKTINFO .Pp For .Xr sendmsg 2 , -the source address or output interface can be specified by adding +the source address or output interface can be specified by adding an .Dv IP_PKTINFO -to the control part of the message on a +message to the control part of the message on a .Dv SOCK_DGRAM or .Dv SOCK_RAW -socket. +socket. Setting ipi_ifindex will cause the primary address of that +interface to be used; setting ipi_addr will directly choose that address. +The IP_PKTINFO cmsghdr structure from a received message may be used +unchanged, in which case the outgoing message will be sent from the +address the incoming message was received on. +.Pp +Setting the +.Dv IP_PKTINFO +option on a socket, with the same +.Vt struct in_pktinfo +structure, will set the default source address to be used until set +again, unless explicitly overridden on a per-packet basis, as above. .Pp The .Dv IP_PORTALGO @@ -177,6 +188,18 @@ cmsg_level = IPPROTO_IP cmsg_type = IP_RECVDSTADDR .Ed .Pp +For +.Xr sendmsg 2 , +the source address can be specified by adding +.Dv IP_SENDSRCADDR +to the control part of the message on a +.Dv SOCK_DGRAM +or +.Dv SOCK_RAW +socket. The IP_RECVDSTADDR cmsghdr structure from a received message +may be used unchanged, in which case the outgoing message will be sent +from the address the incoming message was received on. +.Pp If the .Dv IP_RECVIF option is enabled on a @@ -197,12 +220,6 @@ cmsg_level = IPPROTO_IP cmsg_type = IP_RECVIF .Ed .Pp -The -.Dv IP_RECVPKTINFO -option is similar to the -.Dv IP_PKTINFO -one, only in this case the inbound information is returned. -.Pp If the .Dv IP_RECVTTL option is enabled on a @@ -452,6 +469,24 @@ An unknown socket option name was given; or the IP option field was improperly formed; an option field was shorter than the minimum value or longer than the option buffer provided. .El +.Sh COMPATIBILITY +The +.Dv IP_RECVPKTINFO +option is used because it is directly compatible with Solaris, AIX, etc., +and the +.Dv IP_PKTINFO +option is intended to be used in their manner, to set the default source +address for outgoing packets on a +.Dv SOCK_DGRAM +or +.Dv SOCK_RAW +socket. For compatibility with Linux, however, if you attempt to set the +.Dv IP_PKTINFO +option, using an integer parameter as a boolean value, this will +transparently manipulate the +.Dv IP_RECVPKTINFO +option instead. Source code compatbility with both environments is thus +maintained. .Sh SEE ALSO .Xr getsockopt 2 , .Xr recv 2 , diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 222de25ef8f..554fc6230a8 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -1,4 +1,4 @@ -/* $NetBSD: in.h,v 1.101 2017/08/10 04:31:58 ryo Exp $ */ +/* $NetBSD: in.h,v 1.102 2018/01/01 00:51:36 christos Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993 @@ -289,8 +289,10 @@ struct ip_opts { #define IP_IPSEC_POLICY 22 /* struct; get/set security policy */ #define IP_RECVTTL 23 /* bool; receive IP TTL w/dgram */ #define IP_MINTTL 24 /* minimum TTL for packet or drop */ -#define IP_PKTINFO 25 /* int; send interface and src addr */ -#define IP_RECVPKTINFO 26 /* int; send interface and dst addr */ +#define IP_PKTINFO 25 /* struct; set default src if/addr */ +#define IP_RECVPKTINFO 26 /* int; receive dst if/addr w/dgram */ + +#define IP_SENDSRCADDR IP_RECVDSTADDR /* FreeBSD compatibility */ /* * Information sent in the control message of a datagram socket for @@ -301,6 +303,8 @@ struct in_pktinfo { unsigned int ipi_ifindex; /* interface index */ }; +#define ipi_spec_dst ipi_addr /* Solaris/Linux compatibility */ + /* * Defaults and limits for options */ diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b2997ba7765..6c38b037589 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.c,v 1.180 2017/12/15 04:03:46 ozaki-r Exp $ */ +/* $NetBSD: in_pcb.c,v 1.181 2018/01/01 00:51:36 christos Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -93,7 +93,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.180 2017/12/15 04:03:46 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.181 2018/01/01 00:51:36 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -204,6 +204,7 @@ in_pcballoc(struct socket *so, void *v) inp->inp_errormtu = -1; inp->inp_portalgo = PORTALGO_DEFAULT; inp->inp_bindportonsend = false; + inp->inp_prefsrcip.s_addr = INADDR_ANY; #if defined(IPSEC) if (ipsec_enabled) { int error = ipsec_init_pcbpolicy(so, &inp->inp_sp); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 4203ad1c67c..c0d64c0092b 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -1,4 +1,4 @@ -/* $NetBSD: in_pcb.h,v 1.64 2017/08/10 04:31:58 ryo Exp $ */ +/* $NetBSD: in_pcb.h,v 1.65 2018/01/01 00:51:36 christos Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -95,6 +95,7 @@ struct inpcb { int inp_errormtu; /* MTU of last xmit status = EMSGSIZE */ uint8_t inp_ip_minttl; bool inp_bindportonsend; + struct in_addr inp_prefsrcip; /* preferred src IP when wild */ }; #define inp_faddr inp_ip.ip_dst @@ -121,11 +122,9 @@ struct inpcb { * Cancels INP_HDRINCL. */ #define INP_RECVTTL 0x0800 /* receive incoming IP TTL */ -#define INP_PKTINFO 0x1000 /* receive dst packet info */ -#define INP_RECVPKTINFO 0x2000 /* receive dst packet info */ +#define INP_RECVPKTINFO 0x1000 /* receive IP dst if/addr */ #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ - INP_RECVIF|INP_RECVTTL|INP_RECVPKTINFO|\ - INP_PKTINFO) + INP_RECVIF|INP_RECVTTL|INP_RECVPKTINFO) #define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) #define inp_lock(inp) solock((inp)->inp_socket) diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index f434b299588..b2c982d6f25 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.363 2017/11/24 14:03:25 roy Exp $ */ +/* $NetBSD: ip_input.c,v 1.364 2018/01/01 00:51:36 christos Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.363 2017/11/24 14:03:25 roy Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.364 2018/01/01 00:51:36 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -1533,15 +1533,6 @@ ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip, if (inpflags & INP_RECVPKTINFO) { struct in_pktinfo ipi; - ipi.ipi_addr = ip->ip_src; - ipi.ipi_ifindex = ifp->if_index; - *mp = sbcreatecontrol(&ipi, - sizeof(ipi), IP_RECVPKTINFO, IPPROTO_IP); - if (*mp) - mp = &(*mp)->m_next; - } - if (inpflags & INP_PKTINFO) { - struct in_pktinfo ipi; ipi.ipi_addr = ip->ip_dst; ipi.ipi_ifindex = ifp->if_index; *mp = sbcreatecontrol(&ipi, diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 84bd7bfbd86..4d8f368783a 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_output.c,v 1.288 2017/12/22 11:22:37 ozaki-r Exp $ */ +/* $NetBSD: ip_output.c,v 1.289 2018/01/01 00:51:36 christos Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.288 2017/12/22 11:22:37 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.289 2018/01/01 00:51:36 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_inet.h" @@ -1081,6 +1081,7 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt) struct ip *ip = &inp->inp_ip; int inpflags = inp->inp_flags; int optval = 0, error = 0; + struct in_pktinfo pktinfo; KASSERT(solocked(so)); @@ -1103,7 +1104,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt) case IP_TOS: case IP_TTL: case IP_MINTTL: - case IP_PKTINFO: case IP_RECVOPTS: case IP_RECVRETOPTS: case IP_RECVDSTADDR: @@ -1135,10 +1135,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt) else \ inpflags &= ~bit; - case IP_PKTINFO: - OPTSET(INP_PKTINFO); - break; - case IP_RECVOPTS: OPTSET(INP_RECVOPTS); break; @@ -1163,6 +1159,45 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt) OPTSET(INP_RECVTTL); break; } + break; + case IP_PKTINFO: + error = sockopt_getint(sopt, &optval); + if (!error) { + /* Linux compatibility */ + OPTSET(INP_RECVPKTINFO); + break; + } + error = sockopt_get(sopt, &pktinfo, sizeof(pktinfo)); + if (error) + break; + + if (pktinfo.ipi_ifindex == 0) { + inp->inp_prefsrcip = pktinfo.ipi_addr; + break; + } + + /* Solaris compatibility */ + struct ifnet *ifp; + struct in_ifaddr *ia; + int s; + + /* pick up primary address */ + s = pserialize_read_enter(); + ifp = if_byindex(pktinfo.ipi_ifindex); + if (ifp == NULL) { + pserialize_read_exit(s); + error = EADDRNOTAVAIL; + break; + } + ia = in_get_ia_from_ifp(ifp); + if (ia == NULL) { + pserialize_read_exit(s); + error = EADDRNOTAVAIL; + break; + } + inp->inp_prefsrcip = IA_SIN(ia)->sin_addr; + pserialize_read_exit(s); + break; break; #undef OPTSET @@ -1239,7 +1274,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt) } break; } - case IP_PKTINFO: case IP_TOS: case IP_TTL: case IP_MINTTL: @@ -1269,10 +1303,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt) #define OPTBIT(bit) (inpflags & bit ? 1 : 0) - case IP_PKTINFO: - optval = OPTBIT(INP_PKTINFO); - break; - case IP_RECVOPTS: optval = OPTBIT(INP_RECVOPTS); break; @@ -1300,6 +1330,35 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt) error = sockopt_setint(sopt, optval); break; + case IP_PKTINFO: + /* XXX these tests fail until size gets propagated */ + /* It needs to be passed through from the caller */ + switch (sopt->sopt_size) { + case sizeof(int): + /* Linux compatibility */ + optval = OPTBIT(INP_RECVPKTINFO); + error = sockopt_setint(sopt, optval); + break; + case sizeof(struct in_pktinfo): + /* Solaris compatibility */ + pktinfo.ipi_ifindex = 0; + pktinfo.ipi_addr = inp->inp_prefsrcip; + error = sockopt_set(sopt, &pktinfo, + sizeof(pktinfo)); + break; + default: + /* + * While size is stuck at 0, and, later, if + * the caller doesn't use an exactly sized + * recipient for the data, default to Linux + * compatibility + */ + optval = OPTBIT(INP_RECVPKTINFO); + error = sockopt_setint(sopt, optval); + break; + } + break; + #if 0 /* defined(IPSEC) */ case IP_IPSEC_POLICY: { @@ -1416,11 +1475,14 @@ ip_setpktopts(struct mbuf *control, struct ip_pktopts *pktopts, int *flags, struct inpcb *inp, kauth_cred_t cred) { struct cmsghdr *cm; - struct in_pktinfo *pktinfo; + struct in_pktinfo pktinfo; int error; pktopts->ippo_imo = inp->inp_moptions; - sockaddr_in_init(&pktopts->ippo_laddr, &inp->inp_laddr, 0); + + struct in_addr *ia = in_nullhost(inp->inp_prefsrcip) ? &inp->inp_laddr : + &inp->inp_prefsrcip; + sockaddr_in_init(&pktopts->ippo_laddr, ia, 0); if (control == NULL) return 0; @@ -1446,13 +1508,23 @@ ip_setpktopts(struct mbuf *control, struct ip_pktopts *pktopts, int *flags, switch (cm->cmsg_type) { case IP_PKTINFO: - if (cm->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo))) + if (cm->cmsg_len != CMSG_LEN(sizeof(pktinfo))) return EINVAL; - - pktinfo = (struct in_pktinfo *)CMSG_DATA(cm); - error = ip_pktinfo_prepare(pktinfo, pktopts, flags, + memcpy(&pktinfo, CMSG_DATA(cm), sizeof(pktinfo)); + error = ip_pktinfo_prepare(&pktinfo, pktopts, flags, cred); - if (error != 0) + if (error) + return error; + break; + case IP_SENDSRCADDR: /* FreeBSD compatibility */ + if (cm->cmsg_len != CMSG_LEN(sizeof(struct in_addr))) + return EINVAL; + pktinfo.ipi_ifindex = 0; + pktinfo.ipi_addr = + ((struct in_pktinfo *)CMSG_DATA(cm))->ipi_addr; + error = ip_pktinfo_prepare(&pktinfo, pktopts, flags, + cred); + if (error) return error; break; default: diff --git a/sys/sys/param.h b/sys/sys/param.h index 97399bd1bcf..e61dc97eaa6 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -1,4 +1,4 @@ -/* $NetBSD: param.h,v 1.554 2017/12/06 08:25:47 knakahara Exp $ */ +/* $NetBSD: param.h,v 1.555 2018/01/01 00:51:36 christos Exp $ */ /*- * Copyright (c) 1982, 1986, 1989, 1993 @@ -67,7 +67,7 @@ * 2.99.9 (299000900) */ -#define __NetBSD_Version__ 899000900 /* NetBSD 8.99.9 */ +#define __NetBSD_Version__ 899001000 /* NetBSD 8.99.10 */ #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \ (m) * 1000000) + (p) * 100) <= __NetBSD_Version__) |
