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
This commit is contained in:
christos 2018-01-01 00:51:36 +00:00
parent fe1f2b747b
commit 645664bc7b
7 changed files with 157 additions and 55 deletions

View File

@ -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 .\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\" .\"
.\" @(#)ip.4 8.2 (Berkeley) 11/30/93 .\" @(#)ip.4 8.2 (Berkeley) 11/30/93
.\" .\"
.Dd August 10, 2017 .Dd December 31, 2017
.Dt IP 4 .Dt IP 4
.Os .Os
.Sh NAME .Sh NAME
@ -96,8 +96,8 @@ setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, buf, ipsec_get_policylen(buf));
.Ed .Ed
.Pp .Pp
The The
.Dv IP_PKTINFO .Dv IP_RECVPKTINFO
option can be used to turn on receiving of information about the source option can be used to turn on receiving of information about the destination
address of the packet, and the interface index. address of the packet, and the interface index.
The information is passed in a The information is passed in a
.Vt struct in_pktinfo .Vt struct in_pktinfo
@ -117,13 +117,24 @@ cmsg_type = IP_PKTINFO
.Pp .Pp
For For
.Xr sendmsg 2 , .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 .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 .Dv SOCK_DGRAM
or or
.Dv SOCK_RAW .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 .Pp
The The
.Dv IP_PORTALGO .Dv IP_PORTALGO
@ -177,6 +188,18 @@ cmsg_level = IPPROTO_IP
cmsg_type = IP_RECVDSTADDR cmsg_type = IP_RECVDSTADDR
.Ed .Ed
.Pp .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 If the
.Dv IP_RECVIF .Dv IP_RECVIF
option is enabled on a option is enabled on a
@ -197,12 +220,6 @@ cmsg_level = IPPROTO_IP
cmsg_type = IP_RECVIF cmsg_type = IP_RECVIF
.Ed .Ed
.Pp .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 If the
.Dv IP_RECVTTL .Dv IP_RECVTTL
option is enabled on a 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 the IP option field was improperly formed; an option field was
shorter than the minimum value or longer than the option buffer provided. shorter than the minimum value or longer than the option buffer provided.
.El .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 .Sh SEE ALSO
.Xr getsockopt 2 , .Xr getsockopt 2 ,
.Xr recv 2 , .Xr recv 2 ,

View File

@ -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 * 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_IPSEC_POLICY 22 /* struct; get/set security policy */
#define IP_RECVTTL 23 /* bool; receive IP TTL w/dgram */ #define IP_RECVTTL 23 /* bool; receive IP TTL w/dgram */
#define IP_MINTTL 24 /* minimum TTL for packet or drop */ #define IP_MINTTL 24 /* minimum TTL for packet or drop */
#define IP_PKTINFO 25 /* int; send interface and src addr */ #define IP_PKTINFO 25 /* struct; set default src if/addr */
#define IP_RECVPKTINFO 26 /* int; send interface and dst 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 * Information sent in the control message of a datagram socket for
@ -301,6 +303,8 @@ struct in_pktinfo {
unsigned int ipi_ifindex; /* interface index */ unsigned int ipi_ifindex; /* interface index */
}; };
#define ipi_spec_dst ipi_addr /* Solaris/Linux compatibility */
/* /*
* Defaults and limits for options * Defaults and limits for options
*/ */

View File

@ -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. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -93,7 +93,7 @@
*/ */
#include <sys/cdefs.h> #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 #ifdef _KERNEL_OPT
#include "opt_inet.h" #include "opt_inet.h"
@ -204,6 +204,7 @@ in_pcballoc(struct socket *so, void *v)
inp->inp_errormtu = -1; inp->inp_errormtu = -1;
inp->inp_portalgo = PORTALGO_DEFAULT; inp->inp_portalgo = PORTALGO_DEFAULT;
inp->inp_bindportonsend = false; inp->inp_bindportonsend = false;
inp->inp_prefsrcip.s_addr = INADDR_ANY;
#if defined(IPSEC) #if defined(IPSEC)
if (ipsec_enabled) { if (ipsec_enabled) {
int error = ipsec_init_pcbpolicy(so, &inp->inp_sp); int error = ipsec_init_pcbpolicy(so, &inp->inp_sp);

View File

@ -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. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -95,6 +95,7 @@ struct inpcb {
int inp_errormtu; /* MTU of last xmit status = EMSGSIZE */ int inp_errormtu; /* MTU of last xmit status = EMSGSIZE */
uint8_t inp_ip_minttl; uint8_t inp_ip_minttl;
bool inp_bindportonsend; bool inp_bindportonsend;
struct in_addr inp_prefsrcip; /* preferred src IP when wild */
}; };
#define inp_faddr inp_ip.ip_dst #define inp_faddr inp_ip.ip_dst
@ -121,11 +122,9 @@ struct inpcb {
* Cancels INP_HDRINCL. * Cancels INP_HDRINCL.
*/ */
#define INP_RECVTTL 0x0800 /* receive incoming IP TTL */ #define INP_RECVTTL 0x0800 /* receive incoming IP TTL */
#define INP_PKTINFO 0x1000 /* receive dst packet info */ #define INP_RECVPKTINFO 0x1000 /* receive IP dst if/addr */
#define INP_RECVPKTINFO 0x2000 /* receive dst packet info */
#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
INP_RECVIF|INP_RECVTTL|INP_RECVPKTINFO|\ INP_RECVIF|INP_RECVTTL|INP_RECVPKTINFO)
INP_PKTINFO)
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb) #define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)
#define inp_lock(inp) solock((inp)->inp_socket) #define inp_lock(inp) solock((inp)->inp_socket)

View File

@ -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. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -91,7 +91,7 @@
*/ */
#include <sys/cdefs.h> #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 #ifdef _KERNEL_OPT
#include "opt_inet.h" #include "opt_inet.h"
@ -1532,15 +1532,6 @@ ip_savecontrol(struct inpcb *inp, struct mbuf **mp, struct ip *ip,
} }
if (inpflags & INP_RECVPKTINFO) { 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; struct in_pktinfo ipi;
ipi.ipi_addr = ip->ip_dst; ipi.ipi_addr = ip->ip_dst;
ipi.ipi_ifindex = ifp->if_index; ipi.ipi_ifindex = ifp->if_index;

View File

@ -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. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -91,7 +91,7 @@
*/ */
#include <sys/cdefs.h> #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 #ifdef _KERNEL_OPT
#include "opt_inet.h" #include "opt_inet.h"
@ -1081,6 +1081,7 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
struct ip *ip = &inp->inp_ip; struct ip *ip = &inp->inp_ip;
int inpflags = inp->inp_flags; int inpflags = inp->inp_flags;
int optval = 0, error = 0; int optval = 0, error = 0;
struct in_pktinfo pktinfo;
KASSERT(solocked(so)); KASSERT(solocked(so));
@ -1103,7 +1104,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
case IP_TOS: case IP_TOS:
case IP_TTL: case IP_TTL:
case IP_MINTTL: case IP_MINTTL:
case IP_PKTINFO:
case IP_RECVOPTS: case IP_RECVOPTS:
case IP_RECVRETOPTS: case IP_RECVRETOPTS:
case IP_RECVDSTADDR: case IP_RECVDSTADDR:
@ -1135,10 +1135,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
else \ else \
inpflags &= ~bit; inpflags &= ~bit;
case IP_PKTINFO:
OPTSET(INP_PKTINFO);
break;
case IP_RECVOPTS: case IP_RECVOPTS:
OPTSET(INP_RECVOPTS); OPTSET(INP_RECVOPTS);
break; break;
@ -1164,6 +1160,45 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
break; break;
} }
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 #undef OPTSET
case IP_MULTICAST_IF: case IP_MULTICAST_IF:
@ -1239,7 +1274,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
} }
break; break;
} }
case IP_PKTINFO:
case IP_TOS: case IP_TOS:
case IP_TTL: case IP_TTL:
case IP_MINTTL: case IP_MINTTL:
@ -1269,10 +1303,6 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
#define OPTBIT(bit) (inpflags & bit ? 1 : 0) #define OPTBIT(bit) (inpflags & bit ? 1 : 0)
case IP_PKTINFO:
optval = OPTBIT(INP_PKTINFO);
break;
case IP_RECVOPTS: case IP_RECVOPTS:
optval = OPTBIT(INP_RECVOPTS); optval = OPTBIT(INP_RECVOPTS);
break; break;
@ -1300,6 +1330,35 @@ ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
error = sockopt_setint(sopt, optval); error = sockopt_setint(sopt, optval);
break; 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) */ #if 0 /* defined(IPSEC) */
case IP_IPSEC_POLICY: 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 inpcb *inp, kauth_cred_t cred)
{ {
struct cmsghdr *cm; struct cmsghdr *cm;
struct in_pktinfo *pktinfo; struct in_pktinfo pktinfo;
int error; int error;
pktopts->ippo_imo = inp->inp_moptions; 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) if (control == NULL)
return 0; return 0;
@ -1446,13 +1508,23 @@ ip_setpktopts(struct mbuf *control, struct ip_pktopts *pktopts, int *flags,
switch (cm->cmsg_type) { switch (cm->cmsg_type) {
case IP_PKTINFO: case IP_PKTINFO:
if (cm->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo))) if (cm->cmsg_len != CMSG_LEN(sizeof(pktinfo)))
return EINVAL; return EINVAL;
memcpy(&pktinfo, CMSG_DATA(cm), sizeof(pktinfo));
pktinfo = (struct in_pktinfo *)CMSG_DATA(cm); error = ip_pktinfo_prepare(&pktinfo, pktopts, flags,
error = ip_pktinfo_prepare(pktinfo, pktopts, flags,
cred); 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; return error;
break; break;
default: default:

View File

@ -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 * Copyright (c) 1982, 1986, 1989, 1993
@ -67,7 +67,7 @@
* 2.99.9 (299000900) * 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) + \ #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
(m) * 1000000) + (p) * 100) <= __NetBSD_Version__) (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)