diff --git a/Makefile b/Makefile index 8f96694..2735797 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,8 @@ FLAGS += -DVERSION=\"$(VERSION)\" FLAGS += -DDUAL_STACK_SOCKETS=$(DUAL_STACK_SOCKETS) PASST_SRCS = arch.c arp.c checksum.c conf.c dhcp.c dhcpv6.c flow.c fwd.c \ - icmp.c igmp.c inany.c iov.c isolation.c lineread.c log.c mld.c ndp.c \ - netlink.c packet.c passt.c pasta.c pcap.c pif.c tap.c tcp.c \ + icmp.c igmp.c inany.c iov.c ip.c isolation.c lineread.c log.c mld.c \ + ndp.c netlink.c packet.c passt.c pasta.c pcap.c pif.c tap.c tcp.c \ tcp_splice.c udp.c util.c QRAP_SRCS = qrap.c SRCS = $(PASST_SRCS) $(QRAP_SRCS) @@ -54,9 +54,9 @@ SRCS = $(PASST_SRCS) $(QRAP_SRCS) MANPAGES = passt.1 pasta.1 qrap.1 PASST_HEADERS = arch.h arp.h checksum.h conf.h dhcp.h dhcpv6.h flow.h fwd.h \ - flow_table.h icmp.h inany.h iov.h isolation.h lineread.h log.h ndp.h \ - netlink.h packet.h passt.h pasta.h pcap.h pif.h siphash.h tap.h tcp.h \ - tcp_conn.h tcp_splice.h udp.h util.h + flow_table.h icmp.h inany.h iov.h ip.h isolation.h lineread.h log.h \ + ndp.h netlink.h packet.h passt.h pasta.h pcap.h pif.h siphash.h tap.h \ + tcp.h tcp_conn.h tcp_splice.h udp.h util.h HEADERS = $(PASST_HEADERS) seccomp.h C := \#include \nstruct tcp_info x = { .tcpi_snd_wnd = 0 }; diff --git a/conf.c b/conf.c index e630140..4a783b8 100644 --- a/conf.c +++ b/conf.c @@ -35,6 +35,7 @@ #include #include "util.h" +#include "ip.h" #include "passt.h" #include "netlink.h" #include "udp.h" diff --git a/dhcp.c b/dhcp.c index 1107728..ff4834a 100644 --- a/dhcp.c +++ b/dhcp.c @@ -25,6 +25,7 @@ #include #include "util.h" +#include "ip.h" #include "checksum.h" #include "packet.h" #include "passt.h" diff --git a/flow.c b/flow.c index d7974d5..5bb24cc 100644 --- a/flow.c +++ b/flow.c @@ -11,6 +11,7 @@ #include #include "util.h" +#include "ip.h" #include "passt.h" #include "siphash.h" #include "inany.h" diff --git a/fwd.c b/fwd.c index 09650b2..a235d13 100644 --- a/fwd.c +++ b/fwd.c @@ -21,6 +21,7 @@ #include #include "util.h" +#include "ip.h" #include "fwd.h" #include "passt.h" #include "lineread.h" diff --git a/icmp.c b/icmp.c index fb2fcaf..49d6dd9 100644 --- a/icmp.c +++ b/icmp.c @@ -33,6 +33,7 @@ #include "packet.h" #include "util.h" +#include "ip.h" #include "passt.h" #include "tap.h" #include "log.h" diff --git a/inany.c b/inany.c index 1c165b1..c8479a7 100644 --- a/inany.c +++ b/inany.c @@ -13,6 +13,7 @@ #include #include "util.h" +#include "ip.h" #include "siphash.h" #include "inany.h" diff --git a/ip.c b/ip.c new file mode 100644 index 0000000..2cc7f65 --- /dev/null +++ b/ip.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* PASST - Plug A Simple Socket Transport + * for qemu/UNIX domain socket mode + * + * PASTA - Pack A Subtle Tap Abstraction + * for network namespace/tap device mode + * + * ip.c - IP related functions + * + * Copyright (c) 2020-2021 Red Hat GmbH + * Author: Stefano Brivio + */ + +#include +#include "util.h" +#include "ip.h" + +#define IPV6_NH_OPT(nh) \ + ((nh) == 0 || (nh) == 43 || (nh) == 44 || (nh) == 50 || \ + (nh) == 51 || (nh) == 60 || (nh) == 135 || (nh) == 139 || \ + (nh) == 140 || (nh) == 253 || (nh) == 254) + +/** + * ipv6_l4hdr() - Find pointer to L4 header in IPv6 packet and extract protocol + * @p: Packet pool, packet number @idx has IPv6 header at @offset + * @idx: Index of packet in pool + * @offset: Pre-calculated IPv6 header offset + * @proto: Filled with L4 protocol number + * @dlen: Data length (payload excluding header extensions), set on return + * + * Return: pointer to L4 header, NULL if not found + */ +char *ipv6_l4hdr(const struct pool *p, int idx, size_t offset, uint8_t *proto, + size_t *dlen) +{ + const struct ipv6_opt_hdr *o; + const struct ipv6hdr *ip6h; + char *base; + int hdrlen; + uint8_t nh; + + base = packet_get(p, idx, 0, 0, NULL); + ip6h = packet_get(p, idx, offset, sizeof(*ip6h), dlen); + if (!ip6h) + return NULL; + + offset += sizeof(*ip6h); + + nh = ip6h->nexthdr; + if (!IPV6_NH_OPT(nh)) + goto found; + + while ((o = packet_get_try(p, idx, offset, sizeof(*o), dlen))) { + nh = o->nexthdr; + hdrlen = (o->hdrlen + 1) * 8; + + if (IPV6_NH_OPT(nh)) + offset += hdrlen; + else + goto found; + } + + return NULL; + +found: + if (nh == 59) + return NULL; + + *proto = nh; + return base + offset; +} diff --git a/ip.h b/ip.h new file mode 100644 index 0000000..9be4778 --- /dev/null +++ b/ip.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2021 Red Hat GmbH + * Author: Stefano Brivio + */ + +#ifndef IP_H +#define IP_H + +#include +#include + +#define IN4_IS_ADDR_UNSPECIFIED(a) \ + (((struct in_addr *)(a))->s_addr == htonl_constant(INADDR_ANY)) +#define IN4_IS_ADDR_BROADCAST(a) \ + (((struct in_addr *)(a))->s_addr == htonl_constant(INADDR_BROADCAST)) +#define IN4_IS_ADDR_LOOPBACK(a) \ + (ntohl(((struct in_addr *)(a))->s_addr) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET) +#define IN4_IS_ADDR_MULTICAST(a) \ + (IN_MULTICAST(ntohl(((struct in_addr *)(a))->s_addr))) +#define IN4_ARE_ADDR_EQUAL(a, b) \ + (((struct in_addr *)(a))->s_addr == ((struct in_addr *)b)->s_addr) +#define IN4ADDR_LOOPBACK_INIT \ + { .s_addr = htonl_constant(INADDR_LOOPBACK) } +#define IN4ADDR_ANY_INIT \ + { .s_addr = htonl_constant(INADDR_ANY) } + +#define L2_BUF_IP4_INIT(proto) \ + { \ + .version = 4, \ + .ihl = 5, \ + .tos = 0, \ + .tot_len = 0, \ + .id = 0, \ + .frag_off = 0, \ + .ttl = 0xff, \ + .protocol = (proto), \ + .saddr = 0, \ + .daddr = 0, \ + } +#define L2_BUF_IP4_PSUM(proto) ((uint32_t)htons_constant(0x4500) + \ + (uint32_t)htons_constant(0xff00 | (proto))) + +#define L2_BUF_IP6_INIT(proto) \ + { \ + .priority = 0, \ + .version = 6, \ + .flow_lbl = { 0 }, \ + .payload_len = 0, \ + .nexthdr = (proto), \ + .hop_limit = 255, \ + .saddr = IN6ADDR_ANY_INIT, \ + .daddr = IN6ADDR_ANY_INIT, \ + } + +struct ipv6hdr { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#if __BYTE_ORDER == __BIG_ENDIAN + uint8_t version:4, + priority:4; +#else + uint8_t priority:4, + version:4; +#endif +#pragma GCC diagnostic pop + uint8_t flow_lbl[3]; + + uint16_t payload_len; + uint8_t nexthdr; + uint8_t hop_limit; + + struct in6_addr saddr; + struct in6_addr daddr; +}; + +struct ipv6_opt_hdr { + uint8_t nexthdr; + uint8_t hdrlen; + /* + * TLV encoded option data follows. + */ +} __attribute__((packed)); /* required for some archs */ + +char *ipv6_l4hdr(const struct pool *p, int idx, size_t offset, uint8_t *proto, + size_t *dlen); +#endif /* IP_H */ diff --git a/ndp.c b/ndp.c index 4c85ab8..c58f4b2 100644 --- a/ndp.c +++ b/ndp.c @@ -28,6 +28,7 @@ #include "checksum.h" #include "util.h" +#include "ip.h" #include "passt.h" #include "tap.h" #include "log.h" diff --git a/qrap.c b/qrap.c index 97f350a..d596706 100644 --- a/qrap.c +++ b/qrap.c @@ -32,6 +32,7 @@ #include #include "util.h" +#include "ip.h" #include "passt.h" #include "arp.h" diff --git a/tap.c b/tap.c index 3a66621..d35d894 100644 --- a/tap.c +++ b/tap.c @@ -45,6 +45,7 @@ #include "checksum.h" #include "util.h" +#include "ip.h" #include "iov.h" #include "passt.h" #include "arp.h" diff --git a/tcp.c b/tcp.c index 560d1d4..e0588f9 100644 --- a/tcp.c +++ b/tcp.c @@ -290,6 +290,7 @@ #include "checksum.h" #include "util.h" +#include "ip.h" #include "passt.h" #include "tap.h" #include "siphash.h" diff --git a/tcp_splice.c b/tcp_splice.c index 4957abb..d066112 100644 --- a/tcp_splice.c +++ b/tcp_splice.c @@ -49,6 +49,7 @@ #include #include "util.h" +#include "ip.h" #include "passt.h" #include "log.h" #include "tcp_splice.h" diff --git a/udp.c b/udp.c index cb7c31f..26774df 100644 --- a/udp.c +++ b/udp.c @@ -113,6 +113,7 @@ #include "checksum.h" #include "util.h" +#include "ip.h" #include "siphash.h" #include "inany.h" #include "passt.h" diff --git a/util.c b/util.c index 81449b7..bac5a53 100644 --- a/util.c +++ b/util.c @@ -32,61 +32,6 @@ #include "packet.h" #include "log.h" -#define IPV6_NH_OPT(nh) \ - ((nh) == 0 || (nh) == 43 || (nh) == 44 || (nh) == 50 || \ - (nh) == 51 || (nh) == 60 || (nh) == 135 || (nh) == 139 || \ - (nh) == 140 || (nh) == 253 || (nh) == 254) - -/** - * ipv6_l4hdr() - Find pointer to L4 header in IPv6 packet and extract protocol - * @p: Packet pool, packet number @idx has IPv6 header at @offset - * @idx: Index of packet in pool - * @offset: Pre-calculated IPv6 header offset - * @proto: Filled with L4 protocol number - * @dlen: Data length (payload excluding header extensions), set on return - * - * Return: pointer to L4 header, NULL if not found - */ -char *ipv6_l4hdr(const struct pool *p, int idx, size_t offset, uint8_t *proto, - size_t *dlen) -{ - const struct ipv6_opt_hdr *o; - const struct ipv6hdr *ip6h; - char *base; - int hdrlen; - uint8_t nh; - - base = packet_get(p, idx, 0, 0, NULL); - ip6h = packet_get(p, idx, offset, sizeof(*ip6h), dlen); - if (!ip6h) - return NULL; - - offset += sizeof(*ip6h); - - nh = ip6h->nexthdr; - if (!IPV6_NH_OPT(nh)) - goto found; - - while ((o = packet_get_try(p, idx, offset, sizeof(*o), dlen))) { - nh = o->nexthdr; - hdrlen = (o->hdrlen + 1) * 8; - - if (IPV6_NH_OPT(nh)) - offset += hdrlen; - else - goto found; - } - - return NULL; - -found: - if (nh == 59) - return NULL; - - *proto = nh; - return base + offset; -} - /** * sock_l4() - Create and bind socket for given L4, add to epoll list * @c: Execution context diff --git a/util.h b/util.h index 5551349..25e54a7 100644 --- a/util.h +++ b/util.h @@ -110,22 +110,6 @@ #define htonl_constant(x) (__bswap_constant_32(x)) #endif -#define IN4_IS_ADDR_UNSPECIFIED(a) \ - (((struct in_addr *)(a))->s_addr == htonl_constant(INADDR_ANY)) -#define IN4_IS_ADDR_BROADCAST(a) \ - (((struct in_addr *)(a))->s_addr == htonl_constant(INADDR_BROADCAST)) -#define IN4_IS_ADDR_LOOPBACK(a) \ - (ntohl(((struct in_addr *)(a))->s_addr) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET) -#define IN4_IS_ADDR_MULTICAST(a) \ - (IN_MULTICAST(ntohl(((struct in_addr *)(a))->s_addr))) -#define IN4_ARE_ADDR_EQUAL(a, b) \ - (((struct in_addr *)(a))->s_addr == ((struct in_addr *)b)->s_addr) -#define IN4ADDR_LOOPBACK_INIT \ - { .s_addr = htonl_constant(INADDR_LOOPBACK) } -#define IN4ADDR_ANY_INIT \ - { .s_addr = htonl_constant(INADDR_ANY) } - - #define NS_FN_STACK_SIZE (RLIMIT_STACK_VAL * 1024 / 8) int do_clone(int (*fn)(void *), char *stack_area, size_t stack_size, int flags, void *arg); @@ -138,34 +122,6 @@ int do_clone(int (*fn)(void *), char *stack_area, size_t stack_size, int flags, (void *)(arg)); \ } while (0) -#define L2_BUF_IP4_INIT(proto) \ - { \ - .version = 4, \ - .ihl = 5, \ - .tos = 0, \ - .tot_len = 0, \ - .id = 0, \ - .frag_off = 0, \ - .ttl = 0xff, \ - .protocol = (proto), \ - .saddr = 0, \ - .daddr = 0, \ - } -#define L2_BUF_IP4_PSUM(proto) ((uint32_t)htons_constant(0x4500) + \ - (uint32_t)htons_constant(0xff00 | (proto))) - -#define L2_BUF_IP6_INIT(proto) \ - { \ - .priority = 0, \ - .version = 6, \ - .flow_lbl = { 0 }, \ - .payload_len = 0, \ - .nexthdr = (proto), \ - .hop_limit = 255, \ - .saddr = IN6ADDR_ANY_INIT, \ - .daddr = IN6ADDR_ANY_INIT, \ - } - #define RCVBUF_BIG (2UL * 1024 * 1024) #define SNDBUF_BIG (4UL * 1024 * 1024) #define SNDBUF_SMALL (128UL * 1024) @@ -173,45 +129,13 @@ int do_clone(int (*fn)(void *), char *stack_area, size_t stack_size, int flags, #include #include #include -#include #include "packet.h" struct ctx; -struct ipv6hdr { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#if __BYTE_ORDER == __BIG_ENDIAN - uint8_t version:4, - priority:4; -#else - uint8_t priority:4, - version:4; -#endif -#pragma GCC diagnostic pop - uint8_t flow_lbl[3]; - - uint16_t payload_len; - uint8_t nexthdr; - uint8_t hop_limit; - - struct in6_addr saddr; - struct in6_addr daddr; -}; - -struct ipv6_opt_hdr { - uint8_t nexthdr; - uint8_t hdrlen; - /* - * TLV encoded option data follows. - */ -} __attribute__((packed)); /* required for some archs */ - /* cppcheck-suppress funcArgNamesDifferent */ __attribute__ ((weak)) int ffsl(long int i) { return __builtin_ffsl(i); } -char *ipv6_l4hdr(const struct pool *p, int idx, size_t offset, uint8_t *proto, - size_t *dlen); int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto, const void *bind_addr, const char *ifname, uint16_t port, uint32_t data);