Implement a new IP_SENDSRCADDR ancillary message type that permits
a server process bound to a wildcard UDP socket to select the IP address from which outgoing packets are sent on a per-datagram basis. When combined with IP_RECVDSTADDR, such a server process can guarantee to reply to an incoming request using the same source IP address as the destination IP address of the request, without having to open one socket per server IP address. Discussed on: -net Approved by: re
This commit is contained in:
parent
06f0dd00a0
commit
c557ae16ce
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=105651
@ -136,6 +136,34 @@ cmsg_level = IPPROTO_IP
|
||||
cmsg_type = IP_RECVDSTADDR
|
||||
.Ed
|
||||
.Pp
|
||||
The source address to be used for outgoing
|
||||
.Tn UDP
|
||||
datagrams on a socket that is not bound to a specific
|
||||
.Tn IP
|
||||
address can be specified as ancillary data with a type code of
|
||||
.Dv IP_SENDSRCADDR .
|
||||
The msg_control field in the msghdr structure should point to a buffer
|
||||
that contains a cmsghdr structure followed by the
|
||||
.Tn IP
|
||||
address.
|
||||
The cmsghdr fields should have the following values:
|
||||
.Bd -literal
|
||||
cmsg_len = sizeof(struct in_addr)
|
||||
cmsg_level = IPPROTO_IP
|
||||
cmsg_type = IP_SENDSRCADDR
|
||||
.Ed
|
||||
.Pp
|
||||
For convenience,
|
||||
.Dv IP_SENDSRCADDR
|
||||
is defined to have the same value as
|
||||
.Dv IP_RECVDSTADDR ,
|
||||
so the
|
||||
.Dv IP_RECVDSTADDR
|
||||
control message from
|
||||
.Xr recvmsg 2
|
||||
can be used directly as a control message for
|
||||
.Xr sendmsg 2 .
|
||||
.Pp
|
||||
.Dv IP_PORTRANGE
|
||||
may be used to set the port range used for selecting a local port number
|
||||
on a socket with an unspecified (zero) port number.
|
||||
|
@ -366,6 +366,7 @@ __END_DECLS
|
||||
#define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */
|
||||
#define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */
|
||||
#define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */
|
||||
#define IP_SENDSRCADDR IP_RECVDSTADDR /* cmsg_type to set src addr */
|
||||
#define IP_RETOPTS 8 /* ip_opts; set/get IP options */
|
||||
#define IP_MULTICAST_IF 9 /* u_char; set/get IP multicast i/f */
|
||||
#define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */
|
||||
|
@ -689,7 +689,8 @@ udp_output(inp, m, addr, control, td)
|
||||
register struct udpiphdr *ui;
|
||||
register int len = m->m_pkthdr.len;
|
||||
struct in_addr faddr, laddr;
|
||||
struct sockaddr_in *sin;
|
||||
struct cmsghdr *cm;
|
||||
struct sockaddr_in *sin, src;
|
||||
int error = 0;
|
||||
u_short fport, lport;
|
||||
|
||||
@ -697,16 +698,73 @@ udp_output(inp, m, addr, control, td)
|
||||
mac_create_mbuf_from_socket(inp->inp_socket, m);
|
||||
#endif
|
||||
|
||||
if (control)
|
||||
m_freem(control); /* XXX */
|
||||
|
||||
if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
|
||||
error = EMSGSIZE;
|
||||
if (control)
|
||||
m_freem(control);
|
||||
goto release;
|
||||
}
|
||||
|
||||
src.sin_addr.s_addr = INADDR_ANY;
|
||||
if (control != NULL) {
|
||||
/*
|
||||
* XXX: Currently, we assume all the optional information
|
||||
* is stored in a single mbuf.
|
||||
*/
|
||||
if (control->m_next) {
|
||||
error = EINVAL;
|
||||
m_freem(control);
|
||||
goto release;
|
||||
}
|
||||
for (; control->m_len > 0;
|
||||
control->m_data += CMSG_ALIGN(cm->cmsg_len),
|
||||
control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
|
||||
cm = mtod(control, struct cmsghdr *);
|
||||
if (control->m_len < sizeof(*cm) || cm->cmsg_len == 0 ||
|
||||
cm->cmsg_len > control->m_len) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (cm->cmsg_level != IPPROTO_IP)
|
||||
continue;
|
||||
|
||||
switch (cm->cmsg_type) {
|
||||
case IP_SENDSRCADDR:
|
||||
if (cm->cmsg_len !=
|
||||
CMSG_LEN(sizeof(struct in_addr))) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
bzero(&src, sizeof(src));
|
||||
src.sin_family = AF_INET;
|
||||
src.sin_len = sizeof(src);
|
||||
src.sin_port = inp->inp_lport;
|
||||
src.sin_addr = *(struct in_addr *)CMSG_DATA(cm);
|
||||
break;
|
||||
default:
|
||||
error = ENOPROTOOPT;
|
||||
break;
|
||||
}
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
m_freem(control);
|
||||
}
|
||||
if (error)
|
||||
goto release;
|
||||
laddr = inp->inp_laddr;
|
||||
lport = inp->inp_lport;
|
||||
if (src.sin_addr.s_addr != INADDR_ANY) {
|
||||
if (lport == 0) {
|
||||
error = EINVAL;
|
||||
goto release;
|
||||
}
|
||||
error = in_pcbbind_setup(inp, (struct sockaddr *)&src,
|
||||
&laddr.s_addr, &lport, td);
|
||||
if (error)
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (addr) {
|
||||
sin = (struct sockaddr_in *)addr;
|
||||
if (td && jailed(td->td_ucred))
|
||||
|
Loading…
Reference in New Issue
Block a user