summaryrefslogtreecommitdiff
path: root/src/openvpn/proto.h
blob: c25176741752823d50aef12acead93dd24ecbfb3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/*
 *  OpenVPN -- An application to securely tunnel IP networks
 *             over a single TCP/UDP port, with support for SSL/TLS-based
 *             session authentication and key exchange,
 *             packet encryption, packet authentication, and
 *             packet compression.
 *
 *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef PROTO_H
#define PROTO_H

#include "common.h"
#include "buffer.h"

#pragma pack(1)

/*
 * Tunnel types
 */
#define DEV_TYPE_UNDEF 0
#define DEV_TYPE_NULL  1
#define DEV_TYPE_TUN   2    /* point-to-point IP tunnel */
#define DEV_TYPE_TAP   3    /* ethernet (802.3) tunnel */

/* TUN topologies */

#define TOP_UNDEF   0
#define TOP_NET30   1
#define TOP_P2P     2
#define TOP_SUBNET  3

/*
 * IP and Ethernet protocol structs.  For portability,
 * OpenVPN needs its own definitions of these structs, and
 * names have been adjusted to avoid collisions with
 * native structs.
 */

#define OPENVPN_ETH_ALEN 6            /* ethernet address length */
struct openvpn_ethhdr
{
    uint8_t dest[OPENVPN_ETH_ALEN];   /* destination ethernet addr */
    uint8_t source[OPENVPN_ETH_ALEN]; /* source ethernet addr   */

#define OPENVPN_ETH_P_IPV4   0x0800   /* IPv4 protocol */
#define OPENVPN_ETH_P_IPV6   0x86DD   /* IPv6 protocol */
#define OPENVPN_ETH_P_ARP    0x0806   /* ARP protocol */
#define OPENVPN_ETH_P_8021Q  0x8100   /* 802.1Q protocol */
    uint16_t proto;                   /* packet type ID field */
};

struct openvpn_8021qhdr
{
    uint8_t dest[OPENVPN_ETH_ALEN];     /* destination ethernet addr */
    uint8_t source[OPENVPN_ETH_ALEN];   /* source ethernet addr */

    uint16_t tpid;                      /* 802.1Q Tag Protocol Identifier */
#define OPENVPN_8021Q_MASK_PCP htons(0xE000) /* mask PCP out of pcp_cfi_vid */
#define OPENVPN_8021Q_MASK_CFI htons(0x1000) /* mask CFI out of pcp_cfi_vid */
#define OPENVPN_8021Q_MASK_VID htons(0x0FFF) /* mask VID out of pcp_cfi_vid */
    uint16_t pcp_cfi_vid;               /* bit fields, see IEEE 802.1Q */
    uint16_t proto;                     /* contained packet type ID field */
};

/*
 * Size difference between a regular Ethernet II header and an Ethernet II
 * header with additional IEEE 802.1Q tagging.
 */
#define SIZE_ETH_TO_8021Q_HDR (sizeof(struct openvpn_8021qhdr) \
                               - sizeof(struct openvpn_ethhdr))


struct openvpn_arp {
#define ARP_MAC_ADDR_TYPE 0x0001
    uint16_t mac_addr_type;     /* 0x0001 */

    uint16_t proto_addr_type;   /* 0x0800 */
    uint8_t mac_addr_size;      /* 0x06 */
    uint8_t proto_addr_size;    /* 0x04 */

#define ARP_REQUEST 0x0001
#define ARP_REPLY   0x0002
    uint16_t arp_command;       /* 0x0001 for ARP request, 0x0002 for ARP reply */

    uint8_t mac_src[OPENVPN_ETH_ALEN];
    in_addr_t ip_src;
    uint8_t mac_dest[OPENVPN_ETH_ALEN];
    in_addr_t ip_dest;
};

struct openvpn_iphdr {
#define OPENVPN_IPH_GET_VER(v) (((v) >> 4) & 0x0F)
#define OPENVPN_IPH_GET_LEN(v) (((v) & 0x0F) << 2)
    uint8_t version_len;

    uint8_t tos;
    uint16_t tot_len;
    uint16_t id;

#define OPENVPN_IP_OFFMASK 0x1fff
    uint16_t frag_off;

    uint8_t ttl;

#define OPENVPN_IPPROTO_IGMP    2  /* IGMP protocol */
#define OPENVPN_IPPROTO_TCP     6  /* TCP protocol */
#define OPENVPN_IPPROTO_UDP    17  /* UDP protocol */
#define OPENVPN_IPPROTO_ICMPV6 58 /* ICMPV6 protocol */
    uint8_t protocol;

    uint16_t check;
    uint32_t saddr;
    uint32_t daddr;
    /*The options start here. */
};

/*
 * IPv6 header
 */
struct openvpn_ipv6hdr {
    uint8_t version_prio;
    uint8_t flow_lbl[3];
    uint16_t payload_len;
    uint8_t nexthdr;
    uint8_t hop_limit;

    struct  in6_addr saddr;
    struct  in6_addr daddr;
};

/*
 * ICMPv6 header
 */
struct openvpn_icmp6hdr {
#define OPENVPN_ICMP6_DESTINATION_UNREACHABLE       1
#define OPENVPN_ND_ROUTER_SOLICIT                 133
#define OPENVPN_ND_ROUTER_ADVERT                  134
#define OPENVPN_ND_NEIGHBOR_SOLICIT               135
#define OPENVPN_ND_NEIGHBOR_ADVERT                136
#define OPENVPN_ND_INVERSE_SOLICIT                141
#define OPENVPN_ND_INVERSE_ADVERT                 142
    uint8_t icmp6_type;
#define OPENVPN_ICMP6_DU_NOROUTE                    0
#define OPENVPN_ICMP6_DU_COMMUNICATION_PROHIBTED    1
    uint8_t icmp6_code;
    uint16_t icmp6_cksum;
    uint8_t icmp6_dataun[4];
};

/*
 * UDP header
 */
struct openvpn_udphdr {
    uint16_t source;
    uint16_t dest;
    uint16_t len;
    uint16_t check;
};

/*
 * TCP header, per RFC 793.
 */
struct openvpn_tcphdr {
    uint16_t source;       /* source port */
    uint16_t dest;         /* destination port */
    uint32_t seq;          /* sequence number */
    uint32_t ack_seq;      /* acknowledgement number */

#define OPENVPN_TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2)
    uint8_t doff_res;

#define OPENVPN_TCPH_FIN_MASK (1<<0)
#define OPENVPN_TCPH_SYN_MASK (1<<1)
#define OPENVPN_TCPH_RST_MASK (1<<2)
#define OPENVPN_TCPH_PSH_MASK (1<<3)
#define OPENVPN_TCPH_ACK_MASK (1<<4)
#define OPENVPN_TCPH_URG_MASK (1<<5)
#define OPENVPN_TCPH_ECE_MASK (1<<6)
#define OPENVPN_TCPH_CWR_MASK (1<<7)
    uint8_t flags;

    uint16_t window;
    uint16_t check;
    uint16_t urg_ptr;
};

#define OPENVPN_TCPOPT_EOL     0
#define OPENVPN_TCPOPT_NOP     1
#define OPENVPN_TCPOPT_MAXSEG  2
#define OPENVPN_TCPOLEN_MAXSEG 4

struct ip_tcp_udp_hdr {
    struct openvpn_iphdr ip;
    union {
        struct openvpn_tcphdr tcp;
        struct openvpn_udphdr udp;
    } u;
};

#pragma pack()

/*
 * The following macro is used to update an
 * internet checksum.  "acc" is a 32-bit
 * accumulation of all the changes to the
 * checksum (adding in old 16-bit words and
 * subtracting out new words), and "cksum"
 * is the checksum value to be updated.
 */
#define ADJUST_CHECKSUM(acc, cksum) { \
        int _acc = acc; \
        _acc += (cksum); \
        if (_acc < 0) { \
            _acc = -_acc; \
            _acc = (_acc >> 16) + (_acc & 0xffff); \
            _acc += _acc >> 16; \
            (cksum) = (uint16_t) ~_acc; \
        } else { \
            _acc = (_acc >> 16) + (_acc & 0xffff); \
            _acc += _acc >> 16; \
            (cksum) = (uint16_t) _acc; \
        } \
}

#define ADD_CHECKSUM_32(acc, u32) { \
        acc += (u32) & 0xffff; \
        acc += (u32) >> 16;    \
}

#define SUB_CHECKSUM_32(acc, u32) { \
        acc -= (u32) & 0xffff; \
        acc -= (u32) >> 16;    \
}

/*
 * We are in a "liberal" position with respect to MSS,
 * i.e. we assume that MSS can be calculated from MTU
 * by subtracting out only the IP and TCP header sizes
 * without options.
 *
 * (RFC 879, section 7).
 */
#define MTU_TO_MSS(mtu) (mtu - sizeof(struct openvpn_iphdr) \
                         - sizeof(struct openvpn_tcphdr))

/*
 * This returns an ip protocol version of packet inside tun
 * and offset of IP header (via parameter).
 */
inline static int
get_tun_ip_ver(int tunnel_type, struct buffer *buf, int *ip_hdr_offset)
{
    int ip_ver = -1;

    /* for tun get ip version from ip header */
    if (tunnel_type == DEV_TYPE_TUN)
    {
        *ip_hdr_offset = 0;
        if (likely(BLEN(buf) >= (int) sizeof(struct openvpn_iphdr)))
        {
            ip_ver = OPENVPN_IPH_GET_VER(*BPTR(buf));
        }
    }
    else if (tunnel_type == DEV_TYPE_TAP)
    {
        *ip_hdr_offset = (int)(sizeof(struct openvpn_ethhdr));
        /* for tap get ip version from eth header */
        if (likely(BLEN(buf) >= *ip_hdr_offset))
        {
            const struct openvpn_ethhdr *eh = (const struct openvpn_ethhdr *) BPTR(buf);
            uint16_t proto = ntohs(eh->proto);
            if (proto == OPENVPN_ETH_P_IPV6)
            {
                ip_ver = 6;
            }
            else if (proto == OPENVPN_ETH_P_IPV4)
            {
                ip_ver = 4;
            }
        }
    }

    return ip_ver;
}

/*
 * If raw tunnel packet is IPv4 or IPv6, return true and increment
 * buffer offset to start of IP header.
 */
bool is_ipv4(int tunnel_type, struct buffer *buf);

bool is_ipv6(int tunnel_type, struct buffer *buf);

/**
 *  Calculates an IP or IPv6 checksum with a pseudo header as required by
 *  TCP, UDP and ICMPv6
 *
 * @param af            - Address family for which the checksum is calculated
 *                        AF_INET or AF_INET6
 * @param payload       - the TCP, ICMPv6 or UDP packet
 * @param len_payload   - length of payload
 * @param src_addr      - Source address of the packet
 * @param dest_addr     - Destination address of the packet
 * @param proto next    - header or IP protocol of the packet
 * @return The calculated checksum in host order
 */
uint16_t
ip_checksum(const sa_family_t af, const uint8_t *payload, const int len_payload,
            const uint8_t *src_addr, const uint8_t *dest_addr,  const int proto);

#ifdef PACKET_TRUNCATION_CHECK
void ipv4_packet_size_verify(const uint8_t *data,
                             const int size,
                             const int tunnel_type,
                             const char
                             *prefix,
                             counter_type *errors);

#endif

#define OPENVPN_8021Q_MIN_VID 1
#define OPENVPN_8021Q_MAX_VID 4094

#endif /* ifndef PROTO_H */