Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: implement IP_RECVTOS for IP_PKTOPTIONS

Currently, it is not easily possible to get TOS/DSCP value of packets from
an incoming TCP stream. The mechanism is there, IP_PKTOPTIONS getsockopt
with IP_RECVTOS set, the same way as incoming TTL can be queried. This is
not actually implemented for TOS, though.

This patch adds this functionality, both for IPv4 (IP_PKTOPTIONS) and IPv6
(IPV6_2292PKTOPTIONS). For IPv4, like in the IP_RECVTTL case, the value of
the TOS field is stored from the other party's ACK.

This is needed for proxies which require DSCP transparency. One such example
is at http://zph.bratcheda.org/.

Signed-off-by: Jiri Benc <jbenc@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jiri Benc and committed by
David S. Miller
4c507d28 7a3198a8

+17 -1
+1 -1
include/linux/ipv6.h
··· 366 366 dontfrag:1; 367 367 __u8 min_hopcount; 368 368 __u8 tclass; 369 - __u8 padding; 369 + __u8 rcv_tclass; 370 370 371 371 __u32 dst_cookie; 372 372
+1
include/net/inet_sock.h
··· 168 168 transparent:1, 169 169 mc_all:1, 170 170 nodefrag:1; 171 + __u8 rcv_tos; 171 172 int uc_index; 172 173 int mc_index; 173 174 __be32 mc_addr;
+1
net/ipv4/af_inet.c
··· 381 381 inet->mc_all = 1; 382 382 inet->mc_index = 0; 383 383 inet->mc_list = NULL; 384 + inet->rcv_tos = 0; 384 385 385 386 sk_refcnt_debug_inc(sk); 386 387
+4
net/ipv4/ip_sockglue.c
··· 1289 1289 int hlim = inet->mc_ttl; 1290 1290 put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim); 1291 1291 } 1292 + if (inet->cmsg_flags & IP_CMSG_TOS) { 1293 + int tos = inet->rcv_tos; 1294 + put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos); 1295 + } 1292 1296 len -= msg.msg_controllen; 1293 1297 return put_user(len, optlen); 1294 1298 }
+1
net/ipv4/tcp_ipv4.c
··· 1463 1463 ireq->opt = NULL; 1464 1464 newinet->mc_index = inet_iif(skb); 1465 1465 newinet->mc_ttl = ip_hdr(skb)->ttl; 1466 + newinet->rcv_tos = ip_hdr(skb)->tos; 1466 1467 inet_csk(newsk)->icsk_ext_hdr_len = 0; 1467 1468 if (inet_opt) 1468 1469 inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;
+1
net/ipv6/af_inet6.c
··· 214 214 inet->mc_ttl = 1; 215 215 inet->mc_index = 0; 216 216 inet->mc_list = NULL; 217 + inet->rcv_tos = 0; 217 218 218 219 if (ipv4_config.no_pmtu_disc) 219 220 inet->pmtudisc = IP_PMTUDISC_DONT;
+4
net/ipv6/ipv6_sockglue.c
··· 1017 1017 int hlim = np->mcast_hops; 1018 1018 put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); 1019 1019 } 1020 + if (np->rxopt.bits.rxtclass) { 1021 + int tclass = np->rcv_tclass; 1022 + put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); 1023 + } 1020 1024 if (np->rxopt.bits.rxoinfo) { 1021 1025 struct in6_pktinfo src_info; 1022 1026 src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
+4
net/ipv6/tcp_ipv6.c
··· 1282 1282 newnp->opt = NULL; 1283 1283 newnp->mcast_oif = inet6_iif(skb); 1284 1284 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 1285 + newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); 1285 1286 1286 1287 /* 1287 1288 * No need to charge this sock to the relevant IPv6 refcnt debug socks count ··· 1361 1360 newnp->opt = NULL; 1362 1361 newnp->mcast_oif = inet6_iif(skb); 1363 1362 newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; 1363 + newnp->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); 1364 1364 1365 1365 /* Clone native IPv6 options from listening socket (if any) 1366 1366 ··· 1564 1562 np->mcast_oif = inet6_iif(opt_skb); 1565 1563 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) 1566 1564 np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; 1565 + if (np->rxopt.bits.rxtclass) 1566 + np->rcv_tclass = ipv6_tclass(ipv6_hdr(skb)); 1567 1567 if (ipv6_opt_accepted(sk, opt_skb)) { 1568 1568 skb_set_owner_r(opt_skb, sk); 1569 1569 opt_skb = xchg(&np->pktoptions, opt_skb);