Browse code

Implement block-ipv6

This can be used to redirect all IPv6 traffic to the tun interface,
effectively black holing the IPv6 traffic. Without ICMPv6 error
messages this will result in timeouts when the server does not send
error codes. block-ipv6 allows client side only blocking on all
platforms that OpenVPN supports IPv6. On Android it is only way to do
sensible IPv6 blocking on Android < 5.0 and broken devices (Samsung).

PATCH V6:
- Rebase on master and run uncrustify on the patch

PATCH V5:
- Fix even more style issues by Antonio
- Remove check for dev == tun as this also works for tap

PATCH V4:
- Fix more style issues reported by Antonio
- Clarify parts of the patch in comments and manpage

PATCH V3:
- Fix style iusses reported by Antonio and accidentily commited parts
- merge udp_checksum and ipv6_checkusm into common ip_checksum method
- Use fake ff80::7 address when no other address is configured.
- Make block-ipv6 also work for server by replying block-ipv6 to all
ipv6 traffic send to the server

Note for the server the process_ip happens before the ipv6 route
lookup so every ipv6 packet, regardless of its source address is
replyied to with a no route to host packet.

Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20181203164818.15756-1-arne@rfc2549.org>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg17977.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Arne Schwabe authored on 2018/12/04 01:48:18
Showing 9 changed files
... ...
@@ -1243,6 +1243,43 @@ Like \-\-redirect\-gateway, but omit actually changing the default
1243 1243
 gateway.  Useful when pushing private subnets.
1244 1244
 .\"*********************************************************
1245 1245
 .TP
1246
+.B \-\-block\-ipv6
1247
+On the client, instead of sending IPv6 packets over the VPN tunnel, all
1248
+IPv6 packets are answered with an ICMPv6 no route host message. On the
1249
+server, all IPv6 packets from clients are answered with an ICMPv6
1250
+no route to host message. This options is intended for cases when IPv6
1251
+should be blocked and other options are not available.
1252
+\.B \-\-block\-ipv6
1253
+will use the remote IPv6 as source address of the ICMPv6 packets if set,
1254
+otherwise will use fe80::7 as source address.
1255
+
1256
+For this option to make sense you actually have to route traffic to the tun
1257
+interface. The following example config block would send all IPv6 traffic to
1258
+OpenVPN and answer all requests with no route to host, effectively blocking
1259
+IPv6.
1260
+
1261
+# client config
1262
+.br
1263
+.B \-\-ifconfig-ipv6
1264
+fd15:53b6:dead::2/64  fd15:53b6:dead::1
1265
+.br
1266
+.B \-\-redirect\-gateway
1267
+ipv6
1268
+.br
1269
+.B \-\-block\-ipv6
1270
+
1271
+# Server config, push a "valid" ipv6 config to the client and block
1272
+# on the server
1273
+.br
1274
+.B \-\-push
1275
+"ifconfig-ipv6 fd15:53b6:dead::2/64  fd15:53b6:dead::1"
1276
+.br
1277
+.B \-\-push
1278
+"redirect\-gateway ipv6"
1279
+.br
1280
+.B \-\-block\-ipv6
1281
+.\"*********************************************************
1282
+.TP
1246 1283
 .B \-\-tun\-mtu n
1247 1284
 Take the TUN device MTU to be
1248 1285
 .B n
... ...
@@ -147,49 +147,6 @@ do_extract(struct dhcp *dhcp, int optlen)
147 147
     return ret;
148 148
 }
149 149
 
150
-static uint16_t
151
-udp_checksum(const uint8_t *buf,
152
-             const int len_udp,
153
-             const uint8_t *src_addr,
154
-             const uint8_t *dest_addr)
155
-{
156
-    uint16_t word16;
157
-    uint32_t sum = 0;
158
-    int i;
159
-
160
-    /* make 16 bit words out of every two adjacent 8 bit words and  */
161
-    /* calculate the sum of all 16 bit words */
162
-    for (i = 0; i < len_udp; i += 2)
163
-    {
164
-        word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
165
-        sum += word16;
166
-    }
167
-
168
-    /* add the UDP pseudo header which contains the IP source and destination addresses */
169
-    for (i = 0; i < 4; i += 2)
170
-    {
171
-        word16 = ((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
172
-        sum += word16;
173
-    }
174
-    for (i = 0; i < 4; i += 2)
175
-    {
176
-        word16 = ((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
177
-        sum += word16;
178
-    }
179
-
180
-    /* the protocol number and the length of the UDP packet */
181
-    sum += (uint16_t) OPENVPN_IPPROTO_UDP + (uint16_t) len_udp;
182
-
183
-    /* keep only the last 16 bits of the 32 bit calculated sum and add the carries */
184
-    while (sum >> 16)
185
-    {
186
-        sum = (sum & 0xFFFF) + (sum >> 16);
187
-    }
188
-
189
-    /* Take the one's complement of sum */
190
-    return ((uint16_t) ~sum);
191
-}
192
-
193 150
 in_addr_t
194 151
 dhcp_extract_router_msg(struct buffer *ipbuf)
195 152
 {
... ...
@@ -210,10 +167,10 @@ dhcp_extract_router_msg(struct buffer *ipbuf)
210 210
 
211 211
             /* recompute the UDP checksum */
212 212
             df->udp.check = 0;
213
-            df->udp.check = htons(udp_checksum((uint8_t *) &df->udp,
214
-                                               sizeof(struct openvpn_udphdr) + sizeof(struct dhcp) + optlen,
215
-                                               (uint8_t *)&df->ip.saddr,
216
-                                               (uint8_t *)&df->ip.daddr));
213
+            df->udp.check = htons(ip_checksum(AF_INET, (uint8_t *)&df->udp,
214
+                                              sizeof(struct openvpn_udphdr) + sizeof(struct dhcp) + optlen,
215
+                                              (uint8_t *)&df->ip.saddr, (uint8_t *)&df->ip.daddr,
216
+                                              OPENVPN_IPPROTO_UDP));
217 217
 
218 218
             /* only return the extracted Router address if DHCPACK */
219 219
             if (message_type == DHCPACK)
... ...
@@ -1412,7 +1412,9 @@ process_incoming_tun(struct context *c)
1412 1412
          * The --passtos and --mssfix options require
1413 1413
          * us to examine the IP header (IPv4 or IPv6).
1414 1414
          */
1415
-        process_ip_header(c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
1415
+        unsigned int flags = PIPV4_PASSTOS | PIP_MSSFIX | PIPV4_CLIENT_NAT
1416
+                             | PIPV6_IMCP_NOHOST_CLIENT;
1417
+        process_ip_header(c, flags, &c->c2.buf);
1416 1418
 
1417 1419
 #ifdef PACKET_TRUNCATION_CHECK
1418 1420
         /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
... ...
@@ -1423,6 +1425,9 @@ process_incoming_tun(struct context *c)
1423 1423
                                 &c->c2.n_trunc_pre_encrypt);
1424 1424
 #endif
1425 1425
 
1426
+    }
1427
+    if (c->c2.buf.len > 0)
1428
+    {
1426 1429
         encrypt_sign(c, true);
1427 1430
     }
1428 1431
     else
... ...
@@ -1433,6 +1438,142 @@ process_incoming_tun(struct context *c)
1433 1433
     gc_free(&gc);
1434 1434
 }
1435 1435
 
1436
+/**
1437
+ * Forges a IPv6 ICMP packet with a no route to host error code from the
1438
+ * IPv6 packet in buf and sends it directly back to the client via the tun
1439
+ * device when used on a client and via the link if used on the server.
1440
+ *
1441
+ * @param buf       - The buf containing the packet for which the icmp6
1442
+ *                    unreachable should be constructed.
1443
+ *
1444
+ * @param client    - determines whether to the send packet back via tun or link
1445
+ */
1446
+void
1447
+ipv6_send_icmp_unreachable(struct context *c, struct buffer *buf, bool client)
1448
+{
1449
+#define MAX_ICMPV6LEN 1280
1450
+    struct openvpn_icmp6hdr icmp6out;
1451
+    CLEAR(icmp6out);
1452
+
1453
+    /*
1454
+     * Get a buffer to the ip packet, is_ipv6 automatically forwards
1455
+     * the buffer to the ip packet
1456
+     */
1457
+    struct buffer inputipbuf = *buf;
1458
+
1459
+    is_ipv6(TUNNEL_TYPE(c->c1.tuntap), &inputipbuf);
1460
+
1461
+    if (BLEN(&inputipbuf) < (int)sizeof(struct openvpn_ipv6hdr))
1462
+    {
1463
+        return;
1464
+    }
1465
+
1466
+    const struct openvpn_ipv6hdr *pip6 = (struct openvpn_ipv6hdr *)BPTR(&inputipbuf);
1467
+
1468
+    /* Copy version, traffic class, flow label from input packet */
1469
+    struct openvpn_ipv6hdr pip6out = *pip6;
1470
+
1471
+    pip6out.version_prio = pip6->version_prio;
1472
+    pip6out.daddr = pip6->saddr;
1473
+
1474
+    /*
1475
+     * Use the IPv6 remote address if we have one, otherwise use a fake one
1476
+     * using the remote address is preferred since it makes debugging and
1477
+     * understanding where the ICMPv6 error originates easier
1478
+     */
1479
+    if (c->options.ifconfig_ipv6_remote)
1480
+    {
1481
+        inet_pton(AF_INET6, c->options.ifconfig_ipv6_remote, &pip6out.saddr);
1482
+    }
1483
+    else
1484
+    {
1485
+        inet_pton(AF_INET6, "fe80::7", &pip6out.saddr);
1486
+    }
1487
+
1488
+    pip6out.nexthdr = OPENVPN_IPPROTO_ICMPV6;
1489
+
1490
+    /*
1491
+     * The ICMPv6 unreachable code worked best in my (arne) tests with Windows,
1492
+     * Linux and Android. Windows did not like the administratively prohibited
1493
+     * return code (no fast fail)
1494
+     */
1495
+    icmp6out.icmp6_type = OPENVPN_ICMP6_DESTINATION_UNREACHABLE;
1496
+    icmp6out.icmp6_code = OPENVPN_ICMP6_DU_NOROUTE;
1497
+
1498
+    int icmpheader_len = sizeof(struct openvpn_ipv6hdr)
1499
+                         + sizeof(struct openvpn_icmp6hdr);
1500
+    int totalheader_len = icmpheader_len;
1501
+
1502
+    if (TUNNEL_TYPE(c->c1.tuntap) == DEV_TYPE_TAP)
1503
+    {
1504
+        totalheader_len += sizeof(struct openvpn_ethhdr);
1505
+    }
1506
+
1507
+    /*
1508
+     * Calculate size for payload, defined in the standard that the resulting
1509
+     * frame should be <= 1280 and have as much as possible of the original
1510
+     * packet
1511
+     */
1512
+    int max_payload_size = min_int(MAX_ICMPV6LEN,
1513
+                                   TUN_MTU_SIZE(&c->c2.frame) - icmpheader_len);
1514
+    int payload_len = min_int(max_payload_size, BLEN(&inputipbuf));
1515
+
1516
+    pip6out.payload_len = htons(sizeof(struct openvpn_icmp6hdr) + payload_len);
1517
+
1518
+    /* Construct the packet as outgoing packet back to the client */
1519
+    struct buffer *outbuf;
1520
+    if (client)
1521
+    {
1522
+        c->c2.to_tun = c->c2.buffers->aux_buf;
1523
+        outbuf = &(c->c2.to_tun);
1524
+    }
1525
+    else
1526
+    {
1527
+        c->c2.to_link = c->c2.buffers->aux_buf;
1528
+        outbuf = &(c->c2.to_link);
1529
+    }
1530
+    ASSERT(buf_init(outbuf, totalheader_len));
1531
+
1532
+    /* Fill the end of the buffer with original packet */
1533
+    ASSERT(buf_safe(outbuf, payload_len));
1534
+    ASSERT(buf_copy_n(outbuf, &inputipbuf, payload_len));
1535
+
1536
+    /* ICMP Header, copy into buffer to allow checksum calculation */
1537
+    ASSERT(buf_write_prepend(outbuf, &icmp6out, sizeof(struct openvpn_icmp6hdr)));
1538
+
1539
+    /* Calculate checksum over the packet and write to header */
1540
+
1541
+    uint16_t new_csum = ip_checksum(AF_INET6, BPTR(outbuf), BLEN(outbuf),
1542
+                                    (const uint8_t *)&pip6out.saddr,
1543
+                                    (uint8_t *)&pip6out.daddr, OPENVPN_IPPROTO_ICMPV6);
1544
+    ((struct openvpn_icmp6hdr *) BPTR(outbuf))->icmp6_cksum = htons(new_csum);
1545
+
1546
+
1547
+    /* IPv6 Header */
1548
+    ASSERT(buf_write_prepend(outbuf, &pip6out, sizeof(struct openvpn_ipv6hdr)));
1549
+
1550
+    /*
1551
+     * Tap mode, we also need to create an Ethernet header.
1552
+     */
1553
+    if (TUNNEL_TYPE(c->c1.tuntap) == DEV_TYPE_TAP)
1554
+    {
1555
+        if (BLEN(buf) < (int)sizeof(struct openvpn_ethhdr))
1556
+        {
1557
+            return;
1558
+        }
1559
+
1560
+        const struct openvpn_ethhdr *orig_ethhdr = (struct openvpn_ethhdr *) BPTR(buf);
1561
+
1562
+        /* Copy frametype and reverse source/destination for the response */
1563
+        struct openvpn_ethhdr ethhdr;
1564
+        memcpy(ethhdr.source, orig_ethhdr->dest, OPENVPN_ETH_ALEN);
1565
+        memcpy(ethhdr.dest, orig_ethhdr->source, OPENVPN_ETH_ALEN);
1566
+        ethhdr.proto = htons(OPENVPN_ETH_P_IPV6);
1567
+        ASSERT(buf_write_prepend(outbuf, &ethhdr, sizeof(struct openvpn_ethhdr)));
1568
+    }
1569
+#undef MAX_ICMPV6LEN
1570
+}
1571
+
1436 1572
 void
1437 1573
 process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
1438 1574
 {
... ...
@@ -1454,6 +1595,10 @@ process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
1454 1454
     {
1455 1455
         flags &= ~PIPV4_EXTRACT_DHCP_ROUTER;
1456 1456
     }
1457
+    if (!c->options.block_ipv6)
1458
+    {
1459
+        flags &= ~(PIPV6_IMCP_NOHOST_CLIENT | PIPV6_IMCP_NOHOST_SERVER);
1460
+    }
1457 1461
 
1458 1462
     if (buf->len > 0)
1459 1463
     {
... ...
@@ -1489,7 +1634,7 @@ process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
1489 1489
                 /* possibly do NAT on packet */
1490 1490
                 if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat)
1491 1491
                 {
1492
-                    const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING;
1492
+                    const int direction = (flags & PIP_OUTGOING) ? CN_INCOMING : CN_OUTGOING;
1493 1493
                     client_nat_transform(c->options.client_nat, &ipbuf, direction);
1494 1494
                 }
1495 1495
                 /* possibly extract a DHCP router message */
... ...
@@ -1507,8 +1652,18 @@ process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
1507 1507
                 /* possibly alter the TCP MSS */
1508 1508
                 if (flags & PIP_MSSFIX)
1509 1509
                 {
1510
-                    mss_fixup_ipv6(&ipbuf, MTU_TO_MSS(TUN_MTU_SIZE_DYNAMIC(&c->c2.frame)));
1510
+                    mss_fixup_ipv6(&ipbuf,
1511
+                                   MTU_TO_MSS(TUN_MTU_SIZE_DYNAMIC(&c->c2.frame)));
1512
+                }
1513
+                if (!(flags & PIP_OUTGOING) && (flags
1514
+                                                &(PIPV6_IMCP_NOHOST_CLIENT | PIPV6_IMCP_NOHOST_SERVER)))
1515
+                {
1516
+                    ipv6_send_icmp_unreachable(c, buf,
1517
+                                               (bool)(flags & PIPV6_IMCP_NOHOST_CLIENT));
1518
+                    /* Drop the IPv6 packet */
1519
+                    buf->len = 0;
1511 1520
                 }
1521
+
1512 1522
             }
1513 1523
         }
1514 1524
     }
... ...
@@ -1689,7 +1844,9 @@ process_outgoing_tun(struct context *c)
1689 1689
      * The --mssfix option requires
1690 1690
      * us to examine the IP header (IPv4 or IPv6).
1691 1691
      */
1692
-    process_ip_header(c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
1692
+    process_ip_header(c,
1693
+                      PIP_MSSFIX | PIPV4_EXTRACT_DHCP_ROUTER | PIPV4_CLIENT_NAT | PIP_OUTGOING,
1694
+                      &c->c2.to_tun);
1693 1695
 
1694 1696
     if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN(&c->c2.frame))
1695 1697
     {
... ...
@@ -286,11 +286,13 @@ void process_outgoing_tun(struct context *c);
286 286
 
287 287
 bool send_control_channel_string(struct context *c, const char *str, int msglevel);
288 288
 
289
-#define PIPV4_PASSTOS         (1<<0)
290
-#define PIP_MSSFIX            (1<<1)         /* v4 and v6 */
291
-#define PIPV4_OUTGOING        (1<<2)
292
-#define PIPV4_EXTRACT_DHCP_ROUTER (1<<3)
293
-#define PIPV4_CLIENT_NAT      (1<<4)
289
+#define PIPV4_PASSTOS                   (1<<0)
290
+#define PIP_MSSFIX                      (1<<1)         /* v4 and v6 */
291
+#define PIP_OUTGOING                    (1<<2)
292
+#define PIPV4_EXTRACT_DHCP_ROUTER       (1<<3)
293
+#define PIPV4_CLIENT_NAT                (1<<4)
294
+#define PIPV6_IMCP_NOHOST_CLIENT        (1<<5)
295
+#define PIPV6_IMCP_NOHOST_SERVER        (1<<6)
294 296
 
295 297
 void process_ip_header(struct context *c, unsigned int flags, struct buffer *buf);
296 298
 
... ...
@@ -2855,7 +2855,7 @@ multi_get_queue(struct mbuf_set *ms)
2855 2855
 
2856 2856
     if (mbuf_extract_item(ms, &item)) /* cleartext IP packet */
2857 2857
     {
2858
-        unsigned int pip_flags = PIPV4_PASSTOS;
2858
+        unsigned int pip_flags = PIPV4_PASSTOS | PIPV6_IMCP_NOHOST_SERVER;
2859 2859
 
2860 2860
         set_prefix(item.instance);
2861 2861
         item.instance->context.c2.buf = item.buffer->buf;
... ...
@@ -225,6 +225,10 @@ static const char usage_message[] =
225 225
     "                  Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
226 226
     "--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n"
227 227
     "                  the default gateway.  Useful when pushing private subnets.\n"
228
+    "--block-ipv6     : (Client) Instead sending IPv6 to the server generate\n"
229
+    "                   ICMPv6 host unreachable messages on the client.\n"
230
+    "                   (Server) Instead of forwarding IPv6 packets send\n"
231
+    "                   ICMPv6 host unreachable packets to the client.\n"
228 232
     "--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n"
229 233
     "--push-peer-info : (client only) push client info to server.\n"
230 234
     "--setenv name value : Set a custom environmental variable to pass to script.\n"
... ...
@@ -6364,6 +6368,11 @@ add_option(struct options *options,
6364 6364
 #endif
6365 6365
         options->routes->flags |= RG_ENABLE;
6366 6366
     }
6367
+    else if (streq(p[0], "block-ipv6") && !p[1])
6368
+    {
6369
+        VERIFY_PERMISSION(OPT_P_ROUTE);
6370
+        options->block_ipv6 = true;
6371
+    }
6367 6372
     else if (streq(p[0], "remote-random-hostname") && !p[1])
6368 6373
     {
6369 6374
         VERIFY_PERMISSION(OPT_P_GENERAL);
... ...
@@ -350,6 +350,7 @@ struct options
350 350
     bool route_delay_defined;
351 351
     struct route_option_list *routes;
352 352
     struct route_ipv6_option_list *routes_ipv6;                 /* IPv6 */
353
+    bool block_ipv6;
353 354
     bool route_nopull;
354 355
     bool route_gateway_via_dhcp;
355 356
     bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
... ...
@@ -98,6 +98,58 @@ is_ipv6(int tunnel_type, struct buffer *buf)
98 98
     return is_ipv_X( tunnel_type, buf, 6 );
99 99
 }
100 100
 
101
+
102
+uint16_t
103
+ip_checksum(const sa_family_t af, const uint8_t *payload, const int len_payload,
104
+            const uint8_t *src_addr, const uint8_t *dest_addr, const int proto)
105
+{
106
+    uint32_t sum = 0;
107
+    int addr_len = (af == AF_INET) ? 4 : 16;
108
+
109
+    /*
110
+     * make 16 bit words out of every two adjacent 8 bit words and  */
111
+    /* calculate the sum of all 16 bit words
112
+     */
113
+    for (int i = 0; i < len_payload; i += 2)
114
+    {
115
+        sum +=  (uint16_t)(((payload[i] << 8) & 0xFF00)
116
+                           +((i + 1 < len_payload) ? (payload[i + 1] & 0xFF) : 0));
117
+
118
+    }
119
+
120
+    /*
121
+     * add the pseudo header which contains the IP source and destination
122
+     * addresses
123
+     */
124
+    for (int i = 0; i < addr_len; i += 2)
125
+    {
126
+        sum += (uint16_t)((src_addr[i] << 8) & 0xFF00) + (src_addr[i + 1] & 0xFF);
127
+
128
+    }
129
+    for (int i = 0; i < addr_len; i += 2)
130
+    {
131
+        sum += (uint16_t)((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i + 1] & 0xFF);
132
+    }
133
+
134
+    /* the length of the payload */
135
+    sum += (uint16_t)len_payload;
136
+
137
+    /* The next header or proto field*/
138
+    sum += (uint16_t)proto;
139
+
140
+    /*
141
+     * keep only the last 16 bits of the 32 bit calculated sum and add
142
+     * the carries
143
+     */
144
+    while (sum >> 16)
145
+    {
146
+        sum = (sum & 0xFFFF) + (sum >> 16);
147
+    }
148
+
149
+    /* Take the one's complement of sum */
150
+    return ((uint16_t) ~sum);
151
+}
152
+
101 153
 #ifdef PACKET_TRUNCATION_CHECK
102 154
 
103 155
 void
... ...
@@ -95,9 +95,10 @@ struct openvpn_iphdr {
95 95
 
96 96
     uint8_t ttl;
97 97
 
98
-#define OPENVPN_IPPROTO_IGMP 2  /* IGMP protocol */
99
-#define OPENVPN_IPPROTO_TCP  6  /* TCP protocol */
100
-#define OPENVPN_IPPROTO_UDP 17  /* UDP protocol */
98
+#define OPENVPN_IPPROTO_IGMP    2  /* IGMP protocol */
99
+#define OPENVPN_IPPROTO_TCP     6  /* TCP protocol */
100
+#define OPENVPN_IPPROTO_UDP    17  /* UDP protocol */
101
+#define OPENVPN_IPPROTO_ICMPV6 58 /* ICMPV6 protocol */
101 102
     uint8_t protocol;
102 103
 
103 104
     uint16_t check;
... ...
@@ -120,6 +121,24 @@ struct openvpn_ipv6hdr {
120 120
     struct  in6_addr daddr;
121 121
 };
122 122
 
123
+/*
124
+ * ICMPv6 header
125
+ */
126
+struct openvpn_icmp6hdr {
127
+#define OPENVPN_ICMP6_DESTINATION_UNREACHABLE       1
128
+#define OPENVPN_ND_ROUTER_SOLICIT                 133
129
+#define OPENVPN_ND_ROUTER_ADVERT                  134
130
+#define OPENVPN_ND_NEIGHBOR_SOLICIT               135
131
+#define OPENVPN_ND_NEIGHBOR_ADVERT                136
132
+#define OPENVPN_ND_INVERSE_SOLICIT                141
133
+#define OPENVPN_ND_INVERSE_ADVERT                 142
134
+    uint8_t icmp6_type;
135
+#define OPENVPN_ICMP6_DU_NOROUTE                    0
136
+#define OPENVPN_ICMP6_DU_COMMUNICATION_PROHIBTED    1
137
+    uint8_t icmp6_code;
138
+    uint16_t icmp6_cksum;
139
+    uint8_t icmp6_dataun[4];
140
+};
123 141
 
124 142
 /*
125 143
  * UDP header
... ...
@@ -265,6 +284,23 @@ bool is_ipv4(int tunnel_type, struct buffer *buf);
265 265
 
266 266
 bool is_ipv6(int tunnel_type, struct buffer *buf);
267 267
 
268
+/**
269
+ *  Calculates an IP or IPv6 checksum with a pseudo header as required by
270
+ *  TCP, UDP and ICMPv6
271
+ *
272
+ * @param af            - Address family for which the checksum is calculated
273
+ *                        AF_INET or AF_INET6
274
+ * @param payload       - the TCP, ICMPv6 or UDP packet
275
+ * @param len_payload   - length of payload
276
+ * @param src_addr      - Source address of the packet
277
+ * @param dest_addr     - Destination address of the packet
278
+ * @param proto next    - header or IP protocol of the packet
279
+ * @return The calculated checksum in host order
280
+ */
281
+uint16_t
282
+ip_checksum(const sa_family_t af, const uint8_t *payload, const int len_payload,
283
+            const uint8_t *src_addr, const uint8_t *dest_addr,  const int proto);
284
+
268 285
 #ifdef PACKET_TRUNCATION_CHECK
269 286
 void ipv4_packet_size_verify(const uint8_t *data,
270 287
                              const int size,