GitHub CI: update list of container images
[tinc] / src / route.c
index 3beb2f4..6f1ffd4 100644 (file)
@@ -1,7 +1,7 @@
 /*
     route.c -- routing
     Copyright (C) 2000-2005 Ivo Timmermans,
-                  2000-2013 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2018 Guus Sliepen <guus@tinc-vpn.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -22,6 +22,7 @@
 
 #include "connection.h"
 #include "control_common.h"
+#include "crypto.h"
 #include "ethernet.h"
 #include "ipv4.h"
 #include "ipv6.h"
@@ -55,38 +56,31 @@ static const size_t icmp6_size = sizeof(struct icmp6_hdr);
 static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
 static const size_t opt_size = sizeof(struct nd_opt_hdr);
 
-#ifndef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
-volatile int dummy;
 static timeout_t age_subnets_timeout;
 
 /* RFC 1071 */
 
-static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
-       uint16_t *p = data;
+static uint16_t inet_checksum(void *vdata, size_t len, uint16_t prevsum) {
+       uint8_t *data = vdata;
+       uint16_t word;
        uint32_t checksum = prevsum ^ 0xFFFF;
 
        while(len >= 2) {
-               checksum += *p++;
+               memcpy(&word, data, sizeof(word));
+               checksum += word;
+               data += 2;
                len -= 2;
        }
 
        if(len) {
-               checksum += *(uint8_t *)p;
+               checksum += *data;
        }
 
        while(checksum >> 16) {
                checksum = (checksum & 0xFFFF) + (checksum >> 16);
        }
 
-       // Work around a compiler optimization bug.
-       if(checksum) {
-               dummy = 1;
-       }
-
-       return ~checksum;
+       return (uint16_t) ~checksum;
 }
 
 static bool ratelimit(int frequency) {
@@ -165,12 +159,12 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
                                addr.sin_family = AF_INET;
                                socklen_t addrlen = sizeof(addr);
 
-                               if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && addrlen <= sizeof(addr)) {
+                               if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && (size_t)addrlen <= sizeof(addr)) {
                                        ip_dst = addr.sin_addr;
                                }
                        }
 
-                       close(sockfd);
+                       closesocket(sockfd);
                }
        }
 
@@ -202,7 +196,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
        ip.ip_src = ip_dst;
        ip.ip_dst = ip_src;
 
-       ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
+       ip.ip_sum = inet_checksum(&ip, ip_size, 0xFFFF);
 
        /* Fill in ICMP header */
 
@@ -210,7 +204,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
        icmp.icmp_code = code;
        icmp.icmp_cksum = 0;
 
-       icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, ~0);
+       icmp.icmp_cksum = inet_checksum(&icmp, icmp_size, 0xFFFF);
        icmp.icmp_cksum = inet_checksum(DATA(packet) + ether_size + ip_size + icmp_size, oldlen, icmp.icmp_cksum);
 
        /* Copy structs on stack back to packet */
@@ -270,12 +264,12 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_
                                addr.sin6_family = AF_INET6;
                                socklen_t addrlen = sizeof(addr);
 
-                               if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && addrlen <= sizeof(addr)) {
+                               if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && (size_t)addrlen <= sizeof(addr)) {
                                        pseudo.ip6_src = addr.sin6_addr;
                                }
                        }
 
-                       close(sockfd);
+                       closesocket(sockfd);
                }
        }
 
@@ -315,7 +309,7 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_
 
        /* Generate checksum */
 
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&pseudo, sizeof(pseudo), 0xFFFF);
        checksum = inet_checksum(&icmp6, icmp6_size, checksum);
        checksum = inet_checksum(DATA(packet) + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
 
@@ -404,7 +398,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
        }
 
        /* Find TCP header */
-       int start = ether_size;
+       size_t start = ether_size;
        uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
 
        if(type == ETH_P_8021Q) {
@@ -489,7 +483,7 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
                csum += csum >> 16;
                csum ^= 0xffff;
                DATA(packet)[start + 16] = csum >> 8;
-               DATA(packet)[start + 17] = csum;
+               DATA(packet)[start + 17] = csum & 0xff;
                break;
        }
 }
@@ -498,7 +492,7 @@ static void age_subnets(void *data) {
        (void)data;
        bool left = false;
 
-       for splay_each(subnet_t, s, myself->subnet_tree) {
+       for splay_each(subnet_t, s, &myself->subnet_tree) {
                if(s->expires && s->expires < now.tv_sec) {
                        if(debug_level >= DEBUG_TRAFFIC) {
                                char netstr[MAXNETSTR];
@@ -508,7 +502,7 @@ static void age_subnets(void *data) {
                                }
                        }
 
-                       for list_each(connection_t, c, connection_list)
+                       for list_each(connection_t, c, &connection_list)
                                if(c->edge) {
                                        send_del_subnet(c, s);
                                }
@@ -523,7 +517,7 @@ static void age_subnets(void *data) {
 
        if(left)
                timeout_set(&age_subnets_timeout, &(struct timeval) {
-               10, rand() % 100000
+               10, jitter()
        });
 }
 
@@ -547,13 +541,13 @@ static void learn_mac(mac_t *address) {
 
                /* And tell all other tinc daemons it's our MAC */
 
-               for list_each(connection_t, c, connection_list)
+               for list_each(connection_t, c, &connection_list)
                        if(c->edge) {
                                send_add_subnet(c, subnet);
                        }
 
                timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval) {
-                       10, rand() % 100000
+                       10, jitter()
                });
        } else {
                if(subnet->expires) {
@@ -576,7 +570,7 @@ static void route_broadcast(node_t *source, vpn_packet_t *packet) {
 static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t ether_size) {
        struct ip ip;
        vpn_packet_t fragment;
-       int maxlen, todo;
+       size_t maxlen, todo;
        uint8_t *offset;
        uint16_t ip_off, origf;
 
@@ -591,20 +585,20 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
        todo = ntohs(ip.ip_len) - ip_size;
 
        if(ether_size + ip_size + todo != packet->len) {
-               logger(DEBUG_TRAFFIC, LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%d)", packet->len, (int)(ether_size + ip_size + todo));
+               logger(DEBUG_TRAFFIC, LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%lu)", packet->len, (unsigned long)(ether_size + ip_size + todo));
                return;
        }
 
        logger(DEBUG_TRAFFIC, LOG_INFO, "Fragmenting packet of %d bytes to %s (%s)", packet->len, dest->name, dest->hostname);
 
        offset = DATA(packet) + ether_size + ip_size;
-       maxlen = (dest->mtu - ether_size - ip_size) & ~0x7;
+       maxlen = (MAX(dest->mtu, 590) - ether_size - ip_size) & ~0x7;
        ip_off = ntohs(ip.ip_off);
        origf = ip_off & ~IP_OFFMASK;
        ip_off &= IP_OFFMASK;
 
        while(todo) {
-               int len = todo > maxlen ? maxlen : todo;
+               size_t len = todo > maxlen ? maxlen : todo;
                memcpy(DATA(&fragment) + ether_size + ip_size, offset, len);
                todo -= len;
                offset += len;
@@ -612,7 +606,7 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
                ip.ip_len = htons(ip_size + len);
                ip.ip_off = htons(ip_off | origf | (todo ? IP_MF : 0));
                ip.ip_sum = 0;
-               ip.ip_sum = inet_checksum(&ip, ip_size, ~0);
+               ip.ip_sum = inet_checksum(&ip, ip_size, 0xFFFF);
                memcpy(DATA(&fragment), DATA(packet), ether_size);
                memcpy(DATA(&fragment) + ether_size, &ip, ip_size);
                fragment.len = ether_size + ip_size + len;
@@ -860,7 +854,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
 
        /* Generate checksum */
 
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&pseudo, sizeof(pseudo), 0xFFFF);
        checksum = inet_checksum(&ns, ns_size, checksum);
 
        if(has_opt) {
@@ -907,7 +901,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
        memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
        DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF;                  /* mangle source address so it looks like it's not from us */
 
-       ip6.ip6_dst = ip6.ip6_src;                               /* swap destination and source protocoll address */
+       ip6.ip6_dst = ip6.ip6_src;                               /* swap destination and source protocol address */
        ip6.ip6_src = ns.nd_ns_target;
 
        if(has_opt) {
@@ -934,7 +928,7 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
 
        /* Generate checksum */
 
-       checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+       checksum = inet_checksum(&pseudo, sizeof(pseudo), 0xFFFF);
        checksum = inet_checksum(&ns, ns_size, checksum);
 
        if(has_opt) {
@@ -1115,7 +1109,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
 static void send_pcap(vpn_packet_t *packet) {
        pcap = false;
 
-       for list_each(connection_t, c, connection_list) {
+       for list_each(connection_t, c, &connection_list) {
                if(!c->status.pcap) {
                        continue;
                }
@@ -1128,7 +1122,7 @@ static void send_pcap(vpn_packet_t *packet) {
                }
 
                if(send_request(c, "%d %d %d", CONTROL, REQ_PCAP, len)) {
-                       send_meta(c, (char *)DATA(packet), len);
+                       send_meta(c, DATA(packet), len);
                }
        }
 }