Use typing to reduce chances of IPv4 endianness errors
We recently corrected some errors handling the endianness of IPv4 addresses. These are very easy errors to make since although we mostly store them in network endianness, we sometimes need to manipulate them in host endianness. To reduce the chances of making such mistakes again, change to always using a (struct in_addr) instead of a bare in_addr_t or uint32_t to store network endian addresses. This makes it harder to accidentally do arithmetic or comparisons on such addresses as if they were host endian. We introduce a number of IN4_IS_ADDR_*() helpers to make it easier to directly work with struct in_addr values. This has the additional benefit of making the IPv4 and IPv6 paths more visually similar. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
dd3470d9a9
commit
7c7b68dbe0
14 changed files with 113 additions and 100 deletions
|
@ -133,7 +133,8 @@ void csum_ip4_header(struct iphdr *ip4h)
|
||||||
* @payload: ICMPv4 packet payload
|
* @payload: ICMPv4 packet payload
|
||||||
* @len: Length of @payload (not including UDP)
|
* @len: Length of @payload (not including UDP)
|
||||||
*/
|
*/
|
||||||
void csum_udp4(struct udphdr *udp4hr, in_addr_t saddr, in_addr_t daddr,
|
void csum_udp4(struct udphdr *udp4hr,
|
||||||
|
struct in_addr saddr, struct in_addr daddr,
|
||||||
const void *payload, size_t len)
|
const void *payload, size_t len)
|
||||||
{
|
{
|
||||||
/* UDP checksums are optional, so don't bother */
|
/* UDP checksums are optional, so don't bother */
|
||||||
|
@ -142,8 +143,8 @@ void csum_udp4(struct udphdr *udp4hr, in_addr_t saddr, in_addr_t daddr,
|
||||||
if (UDP4_REAL_CHECKSUMS) {
|
if (UDP4_REAL_CHECKSUMS) {
|
||||||
/* UNTESTED: if we did want real UDPv4 checksums, this
|
/* UNTESTED: if we did want real UDPv4 checksums, this
|
||||||
* is roughly what we'd need */
|
* is roughly what we'd need */
|
||||||
uint32_t psum = csum_fold(htonl(saddr))
|
uint32_t psum = csum_fold(saddr.s_addr)
|
||||||
+ csum_fold(htonl(daddr))
|
+ csum_fold(daddr.s_addr)
|
||||||
+ htons(len + sizeof(*udp4hr))
|
+ htons(len + sizeof(*udp4hr))
|
||||||
+ htons(IPPROTO_UDP);
|
+ htons(IPPROTO_UDP);
|
||||||
/* Add in partial checksum for the UDP header alone */
|
/* Add in partial checksum for the UDP header alone */
|
||||||
|
|
|
@ -14,7 +14,8 @@ uint32_t sum_16b(const void *buf, size_t len);
|
||||||
uint16_t csum_fold(uint32_t sum);
|
uint16_t csum_fold(uint32_t sum);
|
||||||
uint16_t csum_unaligned(const void *buf, size_t len, uint32_t init);
|
uint16_t csum_unaligned(const void *buf, size_t len, uint32_t init);
|
||||||
void csum_ip4_header(struct iphdr *ip4h);
|
void csum_ip4_header(struct iphdr *ip4h);
|
||||||
void csum_udp4(struct udphdr *udp4hr, in_addr_t saddr, in_addr_t daddr,
|
void csum_udp4(struct udphdr *udp4hr,
|
||||||
|
struct in_addr saddr, struct in_addr daddr,
|
||||||
const void *payload, size_t len);
|
const void *payload, size_t len);
|
||||||
void csum_icmp4(struct icmphdr *ih, const void *payload, size_t len);
|
void csum_icmp4(struct icmphdr *ih, const void *payload, size_t len);
|
||||||
void csum_udp6(struct udphdr *udp6hr,
|
void csum_udp6(struct udphdr *udp6hr,
|
||||||
|
|
55
conf.c
55
conf.c
|
@ -358,12 +358,12 @@ static void get_dns(struct ctx *c)
|
||||||
int dns4_set, dns6_set, dnss_set, dns_set, fd;
|
int dns4_set, dns6_set, dnss_set, dns_set, fd;
|
||||||
struct in6_addr *dns6 = &c->ip6.dns[0];
|
struct in6_addr *dns6 = &c->ip6.dns[0];
|
||||||
struct fqdn *s = c->dns_search;
|
struct fqdn *s = c->dns_search;
|
||||||
uint32_t *dns4 = &c->ip4.dns[0];
|
struct in_addr *dns4 = &c->ip4.dns[0];
|
||||||
struct lineread resolvconf;
|
struct lineread resolvconf;
|
||||||
int line_len;
|
int line_len;
|
||||||
char *line, *p, *end;
|
char *line, *p, *end;
|
||||||
|
|
||||||
dns4_set = !c->ifi4 || !!*dns4;
|
dns4_set = !c->ifi4 || !IN4_IS_ADDR_UNSPECIFIED(dns4);
|
||||||
dns6_set = !c->ifi6 || !IN6_IS_ADDR_UNSPECIFIED(dns6);
|
dns6_set = !c->ifi6 || !IN6_IS_ADDR_UNSPECIFIED(dns6);
|
||||||
dnss_set = !!*s->n || c->no_dns_search;
|
dnss_set = !!*s->n || c->no_dns_search;
|
||||||
dns_set = (dns4_set && dns6_set) || c->no_dns;
|
dns_set = (dns4_set && dns6_set) || c->no_dns;
|
||||||
|
@ -389,15 +389,15 @@ static void get_dns(struct ctx *c)
|
||||||
dns4 - &c->ip4.dns[0] < ARRAY_SIZE(c->ip4.dns) - 1 &&
|
dns4 - &c->ip4.dns[0] < ARRAY_SIZE(c->ip4.dns) - 1 &&
|
||||||
inet_pton(AF_INET, p + 1, dns4)) {
|
inet_pton(AF_INET, p + 1, dns4)) {
|
||||||
/* We can only access local addresses via the gw redirect */
|
/* We can only access local addresses via the gw redirect */
|
||||||
if (IPV4_IS_LOOPBACK(ntohl(*dns4))) {
|
if (IN4_IS_ADDR_LOOPBACK(dns4)) {
|
||||||
if (c->no_map_gw) {
|
if (c->no_map_gw) {
|
||||||
*dns4 = 0;
|
dns4->s_addr = htonl(INADDR_ANY);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*dns4 = c->ip4.gw;
|
*dns4 = c->ip4.gw;
|
||||||
}
|
}
|
||||||
dns4++;
|
dns4++;
|
||||||
*dns4 = 0;
|
dns4->s_addr = htonl(INADDR_ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dns6_set &&
|
if (!dns6_set &&
|
||||||
|
@ -566,18 +566,19 @@ static unsigned int conf_ip4(unsigned int ifi,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ip4->gw)
|
if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw))
|
||||||
nl_route(0, ifi, AF_INET, &ip4->gw);
|
nl_route(0, ifi, AF_INET, &ip4->gw);
|
||||||
|
|
||||||
if (!ip4->addr)
|
if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addr))
|
||||||
nl_addr(0, ifi, AF_INET, &ip4->addr, &ip4->prefix_len, NULL);
|
nl_addr(0, ifi, AF_INET, &ip4->addr, &ip4->prefix_len, NULL);
|
||||||
|
|
||||||
if (!ip4->prefix_len) {
|
if (!ip4->prefix_len) {
|
||||||
if (IN_CLASSA(ntohl(ip4->addr)))
|
in_addr_t addr = ntohl(ip4->addr.s_addr);
|
||||||
|
if (IN_CLASSA(addr))
|
||||||
ip4->prefix_len = (32 - IN_CLASSA_NSHIFT);
|
ip4->prefix_len = (32 - IN_CLASSA_NSHIFT);
|
||||||
else if (IN_CLASSB(ntohl(ip4->addr)))
|
else if (IN_CLASSB(addr))
|
||||||
ip4->prefix_len = (32 - IN_CLASSB_NSHIFT);
|
ip4->prefix_len = (32 - IN_CLASSB_NSHIFT);
|
||||||
else if (IN_CLASSC(ntohl(ip4->addr)))
|
else if (IN_CLASSC(addr))
|
||||||
ip4->prefix_len = (32 - IN_CLASSC_NSHIFT);
|
ip4->prefix_len = (32 - IN_CLASSC_NSHIFT);
|
||||||
else
|
else
|
||||||
ip4->prefix_len = 32;
|
ip4->prefix_len = 32;
|
||||||
|
@ -588,7 +589,9 @@ static unsigned int conf_ip4(unsigned int ifi,
|
||||||
if (MAC_IS_ZERO(mac))
|
if (MAC_IS_ZERO(mac))
|
||||||
nl_link(0, ifi, mac, 0, 0);
|
nl_link(0, ifi, mac, 0, 0);
|
||||||
|
|
||||||
if (!ip4->gw || !ip4->addr || MAC_IS_ZERO(mac))
|
if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw) ||
|
||||||
|
IN4_IS_ADDR_UNSPECIFIED(&ip4->addr) ||
|
||||||
|
MAC_IS_ZERO(mac))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ifi;
|
return ifi;
|
||||||
|
@ -850,7 +853,7 @@ static void conf_print(const struct ctx *c)
|
||||||
inet_ntop(AF_INET, &c->ip4.gw, buf4, sizeof(buf4)));
|
inet_ntop(AF_INET, &c->ip4.gw, buf4, sizeof(buf4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; c->ip4.dns[i]; i++) {
|
for (i = 0; !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]); i++) {
|
||||||
if (!i)
|
if (!i)
|
||||||
info("DNS:");
|
info("DNS:");
|
||||||
inet_ntop(AF_INET, &c->ip4.dns[i], buf4, sizeof(buf4));
|
inet_ntop(AF_INET, &c->ip4.dns[i], buf4, sizeof(buf4));
|
||||||
|
@ -1088,7 +1091,7 @@ void conf(struct ctx *c, int argc, char **argv)
|
||||||
char *runas = NULL, *logfile = NULL;
|
char *runas = NULL, *logfile = NULL;
|
||||||
struct in6_addr *dns6 = c->ip6.dns;
|
struct in6_addr *dns6 = c->ip6.dns;
|
||||||
struct fqdn *dnss = c->dns_search;
|
struct fqdn *dnss = c->dns_search;
|
||||||
uint32_t *dns4 = c->ip4.dns;
|
struct in_addr *dns4 = c->ip4.dns;
|
||||||
const char *optstring;
|
const char *optstring;
|
||||||
unsigned int ifi = 0;
|
unsigned int ifi = 0;
|
||||||
int name, ret, b, i;
|
int name, ret, b, i;
|
||||||
|
@ -1186,11 +1189,11 @@ void conf(struct ctx *c, int argc, char **argv)
|
||||||
!IN6_IS_ADDR_LOOPBACK(&c->ip6.dns_fwd))
|
!IN6_IS_ADDR_LOOPBACK(&c->ip6.dns_fwd))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (c->ip4.dns_fwd == htonl(INADDR_ANY) &&
|
if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) &&
|
||||||
inet_pton(AF_INET, optarg, &c->ip4.dns_fwd) &&
|
inet_pton(AF_INET, optarg, &c->ip4.dns_fwd) &&
|
||||||
c->ip4.dns_fwd != htonl(INADDR_ANY) &&
|
!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) &&
|
||||||
c->ip4.dns_fwd != htonl(INADDR_BROADCAST) &&
|
!IN4_IS_ADDR_BROADCAST(&c->ip4.dns_fwd) &&
|
||||||
!IPV4_IS_LOOPBACK(ntohl(c->ip4.dns_fwd)))
|
!IN4_IS_ADDR_LOOPBACK(&c->ip4.dns_fwd))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
err("Invalid DNS forwarding address: %s", optarg);
|
err("Invalid DNS forwarding address: %s", optarg);
|
||||||
|
@ -1384,12 +1387,12 @@ void conf(struct ctx *c, int argc, char **argv)
|
||||||
!IN6_IS_ADDR_MULTICAST(&c->ip6.addr))
|
!IN6_IS_ADDR_MULTICAST(&c->ip6.addr))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (c->ip4.addr == htonl(INADDR_ANY) &&
|
if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr) &&
|
||||||
inet_pton(AF_INET, optarg, &c->ip4.addr) &&
|
inet_pton(AF_INET, optarg, &c->ip4.addr) &&
|
||||||
c->ip4.addr != htonl(INADDR_ANY) &&
|
!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr) &&
|
||||||
c->ip4.addr != htonl(INADDR_BROADCAST) &&
|
!IN4_IS_ADDR_BROADCAST(&c->ip4.addr) &&
|
||||||
!IPV4_IS_LOOPBACK(ntohl(c->ip4.addr)) &&
|
!IN4_IS_ADDR_LOOPBACK(&c->ip4.addr) &&
|
||||||
!IN_MULTICAST(ntohl(c->ip4.addr)))
|
!IN4_IS_ADDR_MULTICAST(&c->ip4.addr))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
err("Invalid address: %s", optarg);
|
err("Invalid address: %s", optarg);
|
||||||
|
@ -1420,11 +1423,11 @@ void conf(struct ctx *c, int argc, char **argv)
|
||||||
!IN6_IS_ADDR_LOOPBACK(&c->ip6.gw))
|
!IN6_IS_ADDR_LOOPBACK(&c->ip6.gw))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (c->ip4.gw == htonl(INADDR_ANY) &&
|
if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw) &&
|
||||||
inet_pton(AF_INET, optarg, &c->ip4.gw) &&
|
inet_pton(AF_INET, optarg, &c->ip4.gw) &&
|
||||||
c->ip4.gw != htonl(INADDR_ANY) &&
|
!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw) &&
|
||||||
c->ip4.gw != htonl(INADDR_BROADCAST) &&
|
!IN4_IS_ADDR_BROADCAST(&c->ip4.gw) &&
|
||||||
!IPV4_IS_LOOPBACK(ntohl(c->ip4.gw)))
|
!IN4_IS_ADDR_LOOPBACK(&c->ip4.gw))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
err("Invalid gateway address: %s", optarg);
|
err("Invalid gateway address: %s", optarg);
|
||||||
|
|
11
dhcp.c
11
dhcp.c
|
@ -107,7 +107,7 @@ struct msg {
|
||||||
uint16_t secs;
|
uint16_t secs;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint32_t ciaddr;
|
uint32_t ciaddr;
|
||||||
uint32_t yiaddr;
|
struct in_addr yiaddr;
|
||||||
uint32_t siaddr;
|
uint32_t siaddr;
|
||||||
uint32_t giaddr;
|
uint32_t giaddr;
|
||||||
uint8_t chaddr[16];
|
uint8_t chaddr[16];
|
||||||
|
@ -343,7 +343,8 @@ int dhcp(const struct ctx *c, const struct pool *p)
|
||||||
/* If the gateway is not on the assigned subnet, send an option 121
|
/* If the gateway is not on the assigned subnet, send an option 121
|
||||||
* (Classless Static Routing) adding a dummy route to it.
|
* (Classless Static Routing) adding a dummy route to it.
|
||||||
*/
|
*/
|
||||||
if ((c->ip4.addr & mask.s_addr) != (c->ip4.gw & mask.s_addr)) {
|
if ((c->ip4.addr.s_addr & mask.s_addr)
|
||||||
|
!= (c->ip4.gw.s_addr & mask.s_addr)) {
|
||||||
/* a.b.c.d/32:0.0.0.0, 0:a.b.c.d */
|
/* a.b.c.d/32:0.0.0.0, 0:a.b.c.d */
|
||||||
opts[121].slen = 14;
|
opts[121].slen = 14;
|
||||||
opts[121].s[0] = 32;
|
opts[121].s[0] = 32;
|
||||||
|
@ -357,8 +358,10 @@ int dhcp(const struct ctx *c, const struct pool *p)
|
||||||
opts[26].s[1] = c->mtu % 256;
|
opts[26].s[1] = c->mtu % 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, opts[6].slen = 0; !c->no_dhcp_dns && c->ip4.dns[i]; i++) {
|
for (i = 0, opts[6].slen = 0;
|
||||||
((uint32_t *)opts[6].s)[i] = c->ip4.dns[i];
|
!c->no_dhcp_dns && !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]);
|
||||||
|
i++) {
|
||||||
|
((struct in_addr *)opts[6].s)[i] = c->ip4.dns[i];
|
||||||
opts[6].slen += sizeof(uint32_t);
|
opts[6].slen += sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
3
icmp.c
3
icmp.c
|
@ -130,8 +130,7 @@ void icmp_sock_handler(const struct ctx *c, union epoll_ref ref,
|
||||||
debug("ICMP: echo %s to tap, ID: %i, seq: %i",
|
debug("ICMP: echo %s to tap, ID: %i, seq: %i",
|
||||||
(ih->type == ICMP_ECHO) ? "request" : "reply", id, seq);
|
(ih->type == ICMP_ECHO) ? "request" : "reply", id, seq);
|
||||||
|
|
||||||
tap_icmp4_send(c, sr4->sin_addr.s_addr, tap_ip4_daddr(c),
|
tap_icmp4_send(c, sr4->sin_addr, tap_ip4_daddr(c), buf, n);
|
||||||
buf, n);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
passt.c
2
passt.c
|
@ -136,7 +136,7 @@ static void timer_init(struct ctx *c, const struct timespec *now)
|
||||||
* @ip_da: Pointer to IPv4 destination address, NULL if unchanged
|
* @ip_da: Pointer to IPv4 destination address, NULL if unchanged
|
||||||
*/
|
*/
|
||||||
void proto_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
void proto_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
const uint32_t *ip_da)
|
const struct in_addr *ip_da)
|
||||||
{
|
{
|
||||||
tcp_update_l2_buf(eth_d, eth_s, ip_da);
|
tcp_update_l2_buf(eth_d, eth_s, ip_da);
|
||||||
udp_update_l2_buf(eth_d, eth_s, ip_da);
|
udp_update_l2_buf(eth_d, eth_s, ip_da);
|
||||||
|
|
12
passt.h
12
passt.h
|
@ -105,12 +105,12 @@ enum passt_modes {
|
||||||
* @dns_fwd: Address forwarded (UDP) to first IPv4 DNS, network order
|
* @dns_fwd: Address forwarded (UDP) to first IPv4 DNS, network order
|
||||||
*/
|
*/
|
||||||
struct ip4_ctx {
|
struct ip4_ctx {
|
||||||
uint32_t addr;
|
struct in_addr addr;
|
||||||
uint32_t addr_seen;
|
struct in_addr addr_seen;
|
||||||
int prefix_len;
|
int prefix_len;
|
||||||
uint32_t gw;
|
struct in_addr gw;
|
||||||
uint32_t dns[MAXNS + 1];
|
struct in_addr dns[MAXNS + 1];
|
||||||
uint32_t dns_fwd;
|
struct in_addr dns_fwd;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -248,6 +248,6 @@ struct ctx {
|
||||||
};
|
};
|
||||||
|
|
||||||
void proto_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
void proto_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
const uint32_t *ip_da);
|
const struct in_addr *ip_da);
|
||||||
|
|
||||||
#endif /* PASST_H */
|
#endif /* PASST_H */
|
||||||
|
|
18
tap.c
18
tap.c
|
@ -92,7 +92,7 @@ int tap_send(const struct ctx *c, const void *data, size_t len)
|
||||||
*
|
*
|
||||||
* Returns: IPv4 address, network order
|
* Returns: IPv4 address, network order
|
||||||
*/
|
*/
|
||||||
in_addr_t tap_ip4_daddr(const struct ctx *c)
|
struct in_addr tap_ip4_daddr(const struct ctx *c)
|
||||||
{
|
{
|
||||||
return c->ip4.addr_seen;
|
return c->ip4.addr_seen;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ static void *tap_push_l2h(const struct ctx *c, void *buf, uint16_t proto)
|
||||||
*
|
*
|
||||||
* Return: pointer at which to write the packet's payload
|
* Return: pointer at which to write the packet's payload
|
||||||
*/
|
*/
|
||||||
static void *tap_push_ip4h(char *buf, in_addr_t src, in_addr_t dst,
|
static void *tap_push_ip4h(char *buf, struct in_addr src, struct in_addr dst,
|
||||||
size_t len, uint8_t proto)
|
size_t len, uint8_t proto)
|
||||||
{
|
{
|
||||||
struct iphdr *ip4h = (struct iphdr *)buf;
|
struct iphdr *ip4h = (struct iphdr *)buf;
|
||||||
|
@ -154,8 +154,8 @@ static void *tap_push_ip4h(char *buf, in_addr_t src, in_addr_t dst,
|
||||||
ip4h->frag_off = 0;
|
ip4h->frag_off = 0;
|
||||||
ip4h->ttl = 255;
|
ip4h->ttl = 255;
|
||||||
ip4h->protocol = proto;
|
ip4h->protocol = proto;
|
||||||
ip4h->saddr = src;
|
ip4h->saddr = src.s_addr;
|
||||||
ip4h->daddr = dst;
|
ip4h->daddr = dst.s_addr;
|
||||||
csum_ip4_header(ip4h);
|
csum_ip4_header(ip4h);
|
||||||
return ip4h + 1;
|
return ip4h + 1;
|
||||||
}
|
}
|
||||||
|
@ -170,8 +170,8 @@ static void *tap_push_ip4h(char *buf, in_addr_t src, in_addr_t dst,
|
||||||
* @in: UDP payload contents (not including UDP header)
|
* @in: UDP payload contents (not including UDP header)
|
||||||
* @len: UDP payload length (not including UDP header)
|
* @len: UDP payload length (not including UDP header)
|
||||||
*/
|
*/
|
||||||
void tap_udp4_send(const struct ctx *c, in_addr_t src, in_port_t sport,
|
void tap_udp4_send(const struct ctx *c, struct in_addr src, in_port_t sport,
|
||||||
in_addr_t dst, in_port_t dport,
|
struct in_addr dst, in_port_t dport,
|
||||||
const void *in, size_t len)
|
const void *in, size_t len)
|
||||||
{
|
{
|
||||||
size_t udplen = len + sizeof(struct udphdr);
|
size_t udplen = len + sizeof(struct udphdr);
|
||||||
|
@ -199,7 +199,7 @@ void tap_udp4_send(const struct ctx *c, in_addr_t src, in_port_t sport,
|
||||||
* @in: ICMP packet, including ICMP header
|
* @in: ICMP packet, including ICMP header
|
||||||
* @len: ICMP packet length, including ICMP header
|
* @len: ICMP packet length, including ICMP header
|
||||||
*/
|
*/
|
||||||
void tap_icmp4_send(const struct ctx *c, in_addr_t src, in_addr_t dst,
|
void tap_icmp4_send(const struct ctx *c, struct in_addr src, struct in_addr dst,
|
||||||
void *in, size_t len)
|
void *in, size_t len)
|
||||||
{
|
{
|
||||||
char buf[USHRT_MAX];
|
char buf[USHRT_MAX];
|
||||||
|
@ -448,8 +448,8 @@ resume:
|
||||||
|
|
||||||
l4_len = l3_len - hlen;
|
l4_len = l3_len - hlen;
|
||||||
|
|
||||||
if (iph->saddr && c->ip4.addr_seen != iph->saddr) {
|
if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr) {
|
||||||
c->ip4.addr_seen = iph->saddr;
|
c->ip4.addr_seen.s_addr = iph->saddr;
|
||||||
proto_update_l2_buf(NULL, NULL, &c->ip4.addr_seen);
|
proto_update_l2_buf(NULL, NULL, &c->ip4.addr_seen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
8
tap.h
8
tap.h
|
@ -6,11 +6,11 @@
|
||||||
#ifndef TAP_H
|
#ifndef TAP_H
|
||||||
#define TAP_H
|
#define TAP_H
|
||||||
|
|
||||||
in_addr_t tap_ip4_daddr(const struct ctx *c);
|
struct in_addr tap_ip4_daddr(const struct ctx *c);
|
||||||
void tap_udp4_send(const struct ctx *c, in_addr_t src, in_port_t sport,
|
void tap_udp4_send(const struct ctx *c, struct in_addr src, in_port_t sport,
|
||||||
in_addr_t dst, in_port_t dport,
|
struct in_addr dst, in_port_t dport,
|
||||||
const void *in, size_t len);
|
const void *in, size_t len);
|
||||||
void tap_icmp4_send(const struct ctx *c, in_addr_t src, in_addr_t dst,
|
void tap_icmp4_send(const struct ctx *c, struct in_addr src, struct in_addr dst,
|
||||||
void *in, size_t len);
|
void *in, size_t len);
|
||||||
const struct in6_addr *tap_ip6_daddr(const struct ctx *c,
|
const struct in6_addr *tap_ip6_daddr(const struct ctx *c,
|
||||||
const struct in6_addr *src);
|
const struct in6_addr *src);
|
||||||
|
|
42
tcp.c
42
tcp.c
|
@ -1107,7 +1107,7 @@ static void tcp_update_check_tcp6(struct tcp6_l2_buf_t *buf)
|
||||||
* @ip_da: Pointer to IPv4 destination address, NULL if unchanged
|
* @ip_da: Pointer to IPv4 destination address, NULL if unchanged
|
||||||
*/
|
*/
|
||||||
void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
const uint32_t *ip_da)
|
const struct in_addr *ip_da)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -1134,15 +1134,15 @@ void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip_da) {
|
if (ip_da) {
|
||||||
b4f->iph.daddr = b4->iph.daddr = *ip_da;
|
b4f->iph.daddr = b4->iph.daddr = ip_da->s_addr;
|
||||||
if (!i) {
|
if (!i) {
|
||||||
b4f->iph.saddr = b4->iph.saddr = 0;
|
b4f->iph.saddr = b4->iph.saddr = 0;
|
||||||
b4f->iph.tot_len = b4->iph.tot_len = 0;
|
b4f->iph.tot_len = b4->iph.tot_len = 0;
|
||||||
b4f->iph.check = b4->iph.check = 0;
|
b4f->iph.check = b4->iph.check = 0;
|
||||||
b4f->psum = b4->psum = sum_16b(&b4->iph, 20);
|
b4f->psum = b4->psum = sum_16b(&b4->iph, 20);
|
||||||
|
|
||||||
b4->tsum = ((*ip_da >> 16) & 0xffff) +
|
b4->tsum = ((ip_da->s_addr >> 16) & 0xffff) +
|
||||||
(*ip_da & 0xffff) +
|
(ip_da->s_addr & 0xffff) +
|
||||||
htons(IPPROTO_TCP);
|
htons(IPPROTO_TCP);
|
||||||
b4f->tsum = b4->tsum;
|
b4f->tsum = b4->tsum;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1701,7 +1701,7 @@ do { \
|
||||||
ip_len = plen + sizeof(struct iphdr) + sizeof(struct tcphdr);
|
ip_len = plen + sizeof(struct iphdr) + sizeof(struct tcphdr);
|
||||||
b->iph.tot_len = htons(ip_len);
|
b->iph.tot_len = htons(ip_len);
|
||||||
b->iph.saddr = conn->a.a4.a.s_addr;
|
b->iph.saddr = conn->a.a4.a.s_addr;
|
||||||
b->iph.daddr = c->ip4.addr_seen;
|
b->iph.daddr = c->ip4.addr_seen.s_addr;
|
||||||
|
|
||||||
if (check)
|
if (check)
|
||||||
b->iph.check = *check;
|
b->iph.check = *check;
|
||||||
|
@ -2048,7 +2048,7 @@ static uint32_t tcp_seq_init(const struct ctx *c, int af, const void *addr,
|
||||||
} __attribute__((__packed__)) in = {
|
} __attribute__((__packed__)) in = {
|
||||||
.src = *(struct in_addr *)addr,
|
.src = *(struct in_addr *)addr,
|
||||||
.srcport = srcport,
|
.srcport = srcport,
|
||||||
.dst = { c->ip4.addr },
|
.dst = c->ip4.addr,
|
||||||
.dstport = dstport,
|
.dstport = dstport,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2176,7 +2176,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!c->no_map_gw) {
|
if (!c->no_map_gw) {
|
||||||
if (af == AF_INET && addr4.sin_addr.s_addr == c->ip4.gw)
|
if (af == AF_INET && IN4_ARE_ADDR_EQUAL(addr, &c->ip4.gw))
|
||||||
addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw))
|
if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw))
|
||||||
addr6.sin6_addr = in6addr_loopback;
|
addr6.sin6_addr = in6addr_loopback;
|
||||||
|
@ -2899,30 +2899,28 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref,
|
||||||
tcp_hash_insert(c, conn, AF_INET6, &sa6.sin6_addr);
|
tcp_hash_insert(c, conn, AF_INET6, &sa6.sin6_addr);
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in sa4;
|
struct sockaddr_in sa4;
|
||||||
in_addr_t s_addr;
|
|
||||||
|
|
||||||
memcpy(&sa4, &sa, sizeof(sa4));
|
memcpy(&sa4, &sa, sizeof(sa4));
|
||||||
s_addr = ntohl(sa4.sin_addr.s_addr);
|
|
||||||
|
|
||||||
memset(&conn->a.a4.zero, 0, sizeof(conn->a.a4.zero));
|
memset(&conn->a.a4.zero, 0, sizeof(conn->a.a4.zero));
|
||||||
memset(&conn->a.a4.one, 0xff, sizeof(conn->a.a4.one));
|
memset(&conn->a.a4.one, 0xff, sizeof(conn->a.a4.one));
|
||||||
|
|
||||||
if (IPV4_IS_LOOPBACK(s_addr) || s_addr == INADDR_ANY ||
|
if (IN4_IS_ADDR_LOOPBACK(&sa4.sin_addr) ||
|
||||||
htonl(s_addr) == c->ip4.addr_seen)
|
IN4_IS_ADDR_UNSPECIFIED(&sa4.sin_addr) ||
|
||||||
s_addr = ntohl(c->ip4.gw);
|
IN4_ARE_ADDR_EQUAL(&sa4.sin_addr, &c->ip4.addr_seen))
|
||||||
|
sa4.sin_addr = c->ip4.gw;
|
||||||
|
|
||||||
s_addr = htonl(s_addr);
|
conn->a.a4.a = sa4.sin_addr;
|
||||||
memcpy(&conn->a.a4.a, &s_addr, sizeof(conn->a.a4.a));
|
|
||||||
|
|
||||||
conn->sock_port = ntohs(sa4.sin_port);
|
conn->sock_port = ntohs(sa4.sin_port);
|
||||||
conn->tap_port = ref.r.p.tcp.tcp.index;
|
conn->tap_port = ref.r.p.tcp.tcp.index;
|
||||||
|
|
||||||
conn->seq_to_tap = tcp_seq_init(c, AF_INET, &s_addr,
|
conn->seq_to_tap = tcp_seq_init(c, AF_INET, &sa4.sin_addr,
|
||||||
conn->sock_port,
|
conn->sock_port,
|
||||||
conn->tap_port,
|
conn->tap_port,
|
||||||
now);
|
now);
|
||||||
|
|
||||||
tcp_hash_insert(c, conn, AF_INET, &s_addr);
|
tcp_hash_insert(c, conn, AF_INET, &sa4.sin_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->seq_ack_from_tap = conn->seq_to_tap + 1;
|
conn->seq_ack_from_tap = conn->seq_to_tap + 1;
|
||||||
|
@ -3081,7 +3079,7 @@ void tcp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events,
|
||||||
* @ifname: Name of interface to bind to, NULL if not configured
|
* @ifname: Name of interface to bind to, NULL if not configured
|
||||||
* @port: Port, host order
|
* @port: Port, host order
|
||||||
*/
|
*/
|
||||||
static void tcp_sock_init4(const struct ctx *c, int ns, const in_addr_t *addr,
|
static void tcp_sock_init4(const struct ctx *c, int ns, const struct in_addr *addr,
|
||||||
const char *ifname, in_port_t port)
|
const char *ifname, in_port_t port)
|
||||||
{
|
{
|
||||||
union tcp_epoll_ref tref = { .tcp.listen = 1, .tcp.outbound = ns };
|
union tcp_epoll_ref tref = { .tcp.listen = 1, .tcp.outbound = ns };
|
||||||
|
@ -3089,14 +3087,13 @@ static void tcp_sock_init4(const struct ctx *c, int ns, const in_addr_t *addr,
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
if (c->mode == MODE_PASTA) {
|
if (c->mode == MODE_PASTA) {
|
||||||
spliced = !addr ||
|
spliced = !addr || IN4_IS_ADDR_UNSPECIFIED(addr) ||
|
||||||
ntohl(*addr) == INADDR_ANY ||
|
IN4_IS_ADDR_LOOPBACK(addr);
|
||||||
IPV4_IS_LOOPBACK(ntohl(*addr));
|
|
||||||
|
|
||||||
if (!addr)
|
if (!addr)
|
||||||
addr = &c->ip4.addr;
|
addr = &c->ip4.addr;
|
||||||
|
|
||||||
tap = !ns && !IPV4_IS_LOOPBACK(ntohl(*addr));
|
tap = !ns && !IN4_IS_ADDR_LOOPBACK(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns)
|
if (ns)
|
||||||
|
@ -3117,9 +3114,10 @@ static void tcp_sock_init4(const struct ctx *c, int ns, const in_addr_t *addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spliced) {
|
if (spliced) {
|
||||||
|
struct in_addr loopback = { htonl(INADDR_LOOPBACK) };
|
||||||
tref.tcp.splice = 1;
|
tref.tcp.splice = 1;
|
||||||
|
|
||||||
addr = &(uint32_t){ htonl(INADDR_LOOPBACK) };
|
addr = &loopback;
|
||||||
|
|
||||||
s = sock_l4(c, AF_INET, IPPROTO_TCP, addr, ifname, port,
|
s = sock_l4(c, AF_INET, IPPROTO_TCP, addr, ifname, port,
|
||||||
tref.u32);
|
tref.u32);
|
||||||
|
|
2
tcp.h
2
tcp.h
|
@ -28,7 +28,7 @@ void tcp_defer_handler(struct ctx *c);
|
||||||
|
|
||||||
void tcp_sock_set_bufsize(const struct ctx *c, int s);
|
void tcp_sock_set_bufsize(const struct ctx *c, int s);
|
||||||
void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
void tcp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
const uint32_t *ip_da);
|
const struct in_addr *ip_da);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* union tcp_epoll_ref - epoll reference portion for TCP connections
|
* union tcp_epoll_ref - epoll reference portion for TCP connections
|
||||||
|
|
30
udp.c
30
udp.c
|
@ -298,7 +298,7 @@ static void udp_update_check4(struct udp4_l2_buf_t *buf)
|
||||||
* @ip_da: Pointer to IPv4 destination address, NULL if unchanged
|
* @ip_da: Pointer to IPv4 destination address, NULL if unchanged
|
||||||
*/
|
*/
|
||||||
void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
const uint32_t *ip_da)
|
const struct in_addr *ip_da)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip_da) {
|
if (ip_da) {
|
||||||
b4->iph.daddr = *ip_da;
|
b4->iph.daddr = ip_da->s_addr;
|
||||||
if (!i) {
|
if (!i) {
|
||||||
b4->iph.saddr = 0;
|
b4->iph.saddr = 0;
|
||||||
b4->iph.tot_len = 0;
|
b4->iph.tot_len = 0;
|
||||||
|
@ -671,30 +671,30 @@ static void udp_sock_fill_data_v4(const struct ctx *c, int n,
|
||||||
struct udp4_l2_buf_t *b = &udp4_l2_buf[n];
|
struct udp4_l2_buf_t *b = &udp4_l2_buf[n];
|
||||||
size_t ip_len, buf_len;
|
size_t ip_len, buf_len;
|
||||||
in_port_t src_port;
|
in_port_t src_port;
|
||||||
in_addr_t src;
|
|
||||||
|
|
||||||
ip_len = udp4_l2_mh_sock[n].msg_len + sizeof(b->iph) + sizeof(b->uh);
|
ip_len = udp4_l2_mh_sock[n].msg_len + sizeof(b->iph) + sizeof(b->uh);
|
||||||
|
|
||||||
b->iph.tot_len = htons(ip_len);
|
b->iph.tot_len = htons(ip_len);
|
||||||
|
|
||||||
src = ntohl(b->s_in.sin_addr.s_addr);
|
|
||||||
src_port = ntohs(b->s_in.sin_port);
|
src_port = ntohs(b->s_in.sin_port);
|
||||||
|
|
||||||
if (IPV4_IS_LOOPBACK(src) ||
|
if (IN4_IS_ADDR_LOOPBACK(&b->s_in.sin_addr) ||
|
||||||
src == INADDR_ANY || src == ntohl(c->ip4.addr_seen)) {
|
IN4_IS_ADDR_UNSPECIFIED(&b->s_in.sin_addr)||
|
||||||
b->iph.saddr = c->ip4.gw;
|
IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.addr_seen)) {
|
||||||
|
b->iph.saddr = c->ip4.gw.s_addr;
|
||||||
udp_tap_map[V4][src_port].ts = now->tv_sec;
|
udp_tap_map[V4][src_port].ts = now->tv_sec;
|
||||||
udp_tap_map[V4][src_port].flags |= PORT_LOCAL;
|
udp_tap_map[V4][src_port].flags |= PORT_LOCAL;
|
||||||
|
|
||||||
if (b->s_in.sin_addr.s_addr == c->ip4.addr_seen)
|
if (IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr.s_addr, &c->ip4.addr_seen))
|
||||||
udp_tap_map[V4][src_port].flags &= ~PORT_LOOPBACK;
|
udp_tap_map[V4][src_port].flags &= ~PORT_LOOPBACK;
|
||||||
else
|
else
|
||||||
udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK;
|
udp_tap_map[V4][src_port].flags |= PORT_LOOPBACK;
|
||||||
|
|
||||||
bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port);
|
bitmap_set(udp_act[V4][UDP_ACT_TAP], src_port);
|
||||||
} else if (c->ip4.dns_fwd &&
|
} else if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_fwd) &&
|
||||||
src == htonl(c->ip4.dns[0]) && src_port == 53) {
|
IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.dns[0]) &&
|
||||||
b->iph.saddr = c->ip4.dns_fwd;
|
src_port == 53) {
|
||||||
|
b->iph.saddr = c->ip4.dns_fwd.s_addr;
|
||||||
} else {
|
} else {
|
||||||
b->iph.saddr = b->s_in.sin_addr.s_addr;
|
b->iph.saddr = b->s_in.sin_addr.s_addr;
|
||||||
}
|
}
|
||||||
|
@ -1016,15 +1016,15 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
|
||||||
|
|
||||||
udp_tap_map[V4][src].ts = now->tv_sec;
|
udp_tap_map[V4][src].ts = now->tv_sec;
|
||||||
|
|
||||||
if (s_in.sin_addr.s_addr == c->ip4.gw && !c->no_map_gw) {
|
if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) && !c->no_map_gw) {
|
||||||
if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
|
if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
|
||||||
(udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
|
(udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
|
||||||
s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
else
|
else
|
||||||
s_in.sin_addr.s_addr = c->ip4.addr_seen;
|
s_in.sin_addr = c->ip4.addr_seen;
|
||||||
} else if (s_in.sin_addr.s_addr == c->ip4.dns_fwd &&
|
} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_fwd) &&
|
||||||
ntohs(s_in.sin_port) == 53) {
|
ntohs(s_in.sin_port) == 53) {
|
||||||
s_in.sin_addr.s_addr = c->ip4.dns[0];
|
s_in.sin_addr = c->ip4.dns[0];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s_in6 = (struct sockaddr_in6) {
|
s_in6 = (struct sockaddr_in6) {
|
||||||
|
|
2
udp.h
2
udp.h
|
@ -17,7 +17,7 @@ void udp_sock_init(const struct ctx *c, int ns, sa_family_t af,
|
||||||
int udp_init(struct ctx *c);
|
int udp_init(struct ctx *c);
|
||||||
void udp_timer(struct ctx *c, const struct timespec *ts);
|
void udp_timer(struct ctx *c, const struct timespec *ts);
|
||||||
void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
void udp_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
|
||||||
const uint32_t *ip_da);
|
const struct in_addr *ip_da);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* union udp_epoll_ref - epoll reference portion for TCP connections
|
* union udp_epoll_ref - epoll reference portion for TCP connections
|
||||||
|
|
12
util.h
12
util.h
|
@ -69,8 +69,16 @@
|
||||||
#define MAC_ZERO ((uint8_t [ETH_ALEN]){ 0 })
|
#define MAC_ZERO ((uint8_t [ETH_ALEN]){ 0 })
|
||||||
#define MAC_IS_ZERO(addr) (!memcmp((addr), MAC_ZERO, ETH_ALEN))
|
#define MAC_IS_ZERO(addr) (!memcmp((addr), MAC_ZERO, ETH_ALEN))
|
||||||
|
|
||||||
#define IPV4_IS_LOOPBACK(addr) \
|
#define IN4_IS_ADDR_UNSPECIFIED(a) \
|
||||||
((addr) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET)
|
((a)->s_addr == htonl(INADDR_ANY))
|
||||||
|
#define IN4_IS_ADDR_BROADCAST(a) \
|
||||||
|
((a)->s_addr == htonl(INADDR_BROADCAST))
|
||||||
|
#define IN4_IS_ADDR_LOOPBACK(a) \
|
||||||
|
(ntohl((a)->s_addr) >> IN_CLASSA_NSHIFT == IN_LOOPBACKNET)
|
||||||
|
#define IN4_IS_ADDR_MULTICAST(a) \
|
||||||
|
(IN_MULTICAST(ntohl((a)->s_addr)))
|
||||||
|
#define IN4_ARE_ADDR_EQUAL(a, b) \
|
||||||
|
(((struct in_addr *)(a))->s_addr == ((struct in_addr *)b)->s_addr)
|
||||||
|
|
||||||
#define NS_FN_STACK_SIZE (RLIMIT_STACK_VAL * 1024 / 8)
|
#define NS_FN_STACK_SIZE (RLIMIT_STACK_VAL * 1024 / 8)
|
||||||
#define NS_CALL(fn, arg) \
|
#define NS_CALL(fn, arg) \
|
||||||
|
|
Loading…
Reference in a new issue