Download raw body.
move udp control parsing to ip_setpktopts
Hi,
I would like to move the parsing code for control messages from
udp_output() to new function ip_setpktopts(). IPv6 has a similar
ip6_setpktopts(). NetBSD also does that. This has the advantage
that raw IP can also use the features. NetBSD also supports modern
interface IP_PKTINFO which I may implement later.
Note that parsing of the cmsg is stricter now. Invalid lengths
generate EINVAL, unknown type ENOPROTOOPT. As NetBSD has the same
checks, I don't expect fallout.
ok?
bluhm
Index: netinet/ip_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_output.c,v
diff -u -p -r1.392 ip_output.c
--- netinet/ip_output.c 1 Dec 2023 15:30:47 -0000 1.392
+++ netinet/ip_output.c 9 Jan 2024 20:04:31 -0000
@@ -85,7 +85,7 @@ static u_int16_t in_cksum_phdr(u_int32_t
void in_delayed_cksum(struct mbuf *);
int ip_output_ipsec_lookup(struct mbuf *m, int hlen, const u_char seclevel[],
- struct tdb **, int ipsecflowinfo);
+ struct tdb **, u_int32_t ipsecflowinfo);
void ip_output_ipsec_pmtu_update(struct tdb *, struct route *, struct in_addr,
int, int);
int ip_output_ipsec_send(struct tdb *, struct mbuf *, struct route *, int);
@@ -510,7 +510,7 @@ bad:
#ifdef IPSEC
int
ip_output_ipsec_lookup(struct mbuf *m, int hlen, const u_char seclevel[],
- struct tdb **tdbout, int ipsecflowinfo)
+ struct tdb **tdbout, u_int32_t ipsecflowinfo)
{
struct m_tag *mtag;
struct tdb_ident *tdbi;
@@ -1755,6 +1755,72 @@ ip_freemoptions(struct ip_moptions *imo)
imo->imo_max_memberships * sizeof(struct in_multi *));
free(imo, M_IPMOPTS, sizeof(*imo));
}
+}
+
+int
+ip_setpktopts(struct mbuf *control, struct sockaddr_in *src,
+ u_int32_t *ipsecflowinfo, const struct inpcb *inp)
+{
+ caddr_t cmsgs;
+ u_int clen;
+ int error;
+
+ if (control == NULL)
+ return (EINVAL);
+
+ /*
+ * XXX: Currently, we assume all the optional information is stored
+ * in a single mbuf.
+ */
+ if (control->m_next)
+ return (EINVAL);
+
+ clen = control->m_len;
+ cmsgs = mtod(control, caddr_t);
+ do {
+ struct cmsghdr *cm;
+
+ if (clen < CMSG_LEN(0))
+ return (EINVAL);
+ cm = (struct cmsghdr *)cmsgs;
+ if (cm->cmsg_len < CMSG_LEN(0) || cm->cmsg_len > clen ||
+ CMSG_ALIGN(cm->cmsg_len) > clen)
+ return (EINVAL);
+ if (cm->cmsg_level == IPPROTO_IP) {
+ switch (cm->cmsg_type) {
+#ifdef IPSEC
+ case IP_IPSECFLOWINFO:
+ if (cm->cmsg_len !=
+ CMSG_LEN(sizeof(u_int32_t)))
+ return (EINVAL);
+ if (!ISSET(inp->inp_flags, INP_IPSECFLOWINFO))
+ break;
+ *ipsecflowinfo = *(u_int32_t *)CMSG_DATA(cm);
+ break;
+#endif
+ case IP_SENDSRCADDR:
+ if (cm->cmsg_len !=
+ CMSG_LEN(sizeof(struct in_addr)))
+ return (EINVAL);
+ src->sin_family = AF_INET;
+ src->sin_len = sizeof(struct sockaddr_in);
+ memcpy(&src->sin_addr, CMSG_DATA(cm),
+ sizeof(struct in_addr));
+ /* no check on reuse when sin->sin_port == 0 */
+ error = in_pcbaddrisavail(inp, src, 0,
+ curproc);
+ if (error)
+ return (error);
+ break;
+ default:
+ return (ENOPROTOOPT);
+ }
+ }
+ clen -= CMSG_ALIGN(cm->cmsg_len);
+ cmsgs += CMSG_ALIGN(cm->cmsg_len);
+ } while (clen);
+
+ return (0);
}
/*
Index: netinet/ip_var.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_var.h,v
diff -u -p -r1.110 ip_var.h
--- netinet/ip_var.h 26 Nov 2023 22:08:10 -0000 1.110
+++ netinet/ip_var.h 9 Jan 2024 20:04:31 -0000
@@ -231,6 +231,8 @@ int ip_fragment(struct mbuf *, struct m
void ip_freemoptions(struct ip_moptions *);
int ip_getmoptions(int, struct ip_moptions *, struct mbuf *);
void ip_init(void);
+int ip_setpktopts(struct mbuf *, struct sockaddr_in *, u_int32_t *,
+ const struct inpcb *);
struct mbuf*
ip_insertoptions(struct mbuf *, struct mbuf *, int *);
int ip_mforward(struct mbuf *, struct ifnet *);
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v
diff -u -p -r1.312 udp_usrreq.c
--- netinet/udp_usrreq.c 1 Dec 2023 15:30:47 -0000 1.312
+++ netinet/udp_usrreq.c 9 Jan 2024 20:04:31 -0000
@@ -932,57 +932,10 @@ udp_output(struct inpcb *inp, struct mbu
}
memset(&src_sin, 0, sizeof(src_sin));
-
if (control) {
- u_int clen;
- struct cmsghdr *cm;
- caddr_t cmsgs;
-
- /*
- * XXX: Currently, we assume all the optional information is
- * stored in a single mbuf.
- */
- if (control->m_next) {
- error = EINVAL;
+ error = ip_setpktopts(control, &src_sin, &ipsecflowinfo, inp);
+ if (error)
goto release;
- }
-
- clen = control->m_len;
- cmsgs = mtod(control, caddr_t);
- do {
- if (clen < CMSG_LEN(0)) {
- error = EINVAL;
- goto release;
- }
- cm = (struct cmsghdr *)cmsgs;
- if (cm->cmsg_len < CMSG_LEN(0) ||
- CMSG_ALIGN(cm->cmsg_len) > clen) {
- error = EINVAL;
- goto release;
- }
-#ifdef IPSEC
- if ((inp->inp_flags & INP_IPSECFLOWINFO) != 0 &&
- cm->cmsg_len == CMSG_LEN(sizeof(ipsecflowinfo)) &&
- cm->cmsg_level == IPPROTO_IP &&
- cm->cmsg_type == IP_IPSECFLOWINFO) {
- ipsecflowinfo = *(u_int32_t *)CMSG_DATA(cm);
- } else
-#endif
- if (cm->cmsg_len == CMSG_LEN(sizeof(struct in_addr)) &&
- cm->cmsg_level == IPPROTO_IP &&
- cm->cmsg_type == IP_SENDSRCADDR) {
- memcpy(&src_sin.sin_addr, CMSG_DATA(cm),
- sizeof(struct in_addr));
- src_sin.sin_family = AF_INET;
- src_sin.sin_len = sizeof(src_sin);
- /* no check on reuse when sin->sin_port == 0 */
- if ((error = in_pcbaddrisavail(inp, &src_sin,
- 0, curproc)))
- goto release;
- }
- clen -= CMSG_ALIGN(cm->cmsg_len);
- cmsgs += CMSG_ALIGN(cm->cmsg_len);
- } while (clen);
}
if (addr) {
Index: netinet6/ip6_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/ip6_output.c,v
diff -u -p -r1.282 ip6_output.c
--- netinet6/ip6_output.c 1 Dec 2023 15:30:47 -0000 1.282
+++ netinet6/ip6_output.c 9 Jan 2024 20:04:31 -0000
@@ -2218,9 +2218,8 @@ int
ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
struct ip6_pktopts *stickyopt, int priv, int uproto)
{
- u_int clen;
- struct cmsghdr *cm = 0;
caddr_t cmsgs;
+ u_int clen;
int error;
if (control == NULL || opt == NULL)
@@ -2228,8 +2227,6 @@ ip6_setpktopts(struct mbuf *control, str
ip6_initpktopts(opt);
if (stickyopt) {
- int error;
-
/*
* If stickyopt is provided, make a local copy of the options
* for this particular packet, then override them by ancillary
@@ -2253,6 +2250,8 @@ ip6_setpktopts(struct mbuf *control, str
clen = control->m_len;
cmsgs = mtod(control, caddr_t);
do {
+ struct cmsghdr *cm;
+
if (clen < CMSG_LEN(0))
return (EINVAL);
cm = (struct cmsghdr *)cmsgs;
@@ -2281,8 +2280,6 @@ int
ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
int priv, int sticky, int uproto)
{
- int minmtupolicy;
-
switch (optname) {
case IPV6_PKTINFO:
{
@@ -2493,6 +2490,9 @@ ip6_setpktopt(int optname, u_char *buf,
}
case IPV6_USE_MIN_MTU:
+ {
+ int minmtupolicy;
+
if (len != sizeof(int))
return (EINVAL);
minmtupolicy = *(int *)buf;
@@ -2503,6 +2503,7 @@ ip6_setpktopt(int optname, u_char *buf,
}
opt->ip6po_minmtu = minmtupolicy;
break;
+ }
case IPV6_DONTFRAG:
if (len != sizeof(int))
move udp control parsing to ip_setpktopts