src/openvpn/proto.h
6fbf66fa
 /*
  *  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.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
6fbf66fa
  *
  *  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.
  *
caa54ac3
  *  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.
6fbf66fa
  */
 
 #ifndef PROTO_H
 #define PROTO_H
 
3c7f2f55
 #include "common.h"
6fbf66fa
 #include "buffer.h"
 
90efcacb
 #pragma pack(1)
 
6fbf66fa
 /*
  * 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 */
 
3c7f2f55
 /* TUN topologies */
 
 #define TOP_UNDEF   0
 #define TOP_NET30   1
 #define TOP_P2P     2
 #define TOP_SUBNET  3
 
6fbf66fa
 /*
  * 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 */
81d882d5
 struct openvpn_ethhdr
6fbf66fa
 {
81d882d5
     uint8_t dest[OPENVPN_ETH_ALEN];   /* destination ethernet addr */
     uint8_t source[OPENVPN_ETH_ALEN]; /* source ethernet addr   */
6fbf66fa
 
81d882d5
 #define OPENVPN_ETH_P_IPV4   0x0800   /* IPv4 protocol */
 #define OPENVPN_ETH_P_IPV6   0x86DD   /* IPv6 protocol */
 #define OPENVPN_ETH_P_ARP    0x0806   /* ARP protocol */
     uint16_t proto;                   /* packet type ID field */
6fbf66fa
 };
 
90efcacb
 struct openvpn_arp {
81d882d5
 #define ARP_MAC_ADDR_TYPE 0x0001
     uint16_t mac_addr_type;     /* 0x0001 */
90efcacb
 
81d882d5
     uint16_t proto_addr_type;   /* 0x0800 */
     uint8_t mac_addr_size;      /* 0x06 */
     uint8_t proto_addr_size;    /* 0x04 */
90efcacb
 
81d882d5
 #define ARP_REQUEST 0x0001
 #define ARP_REPLY   0x0002
     uint16_t arp_command;       /* 0x0001 for ARP request, 0x0002 for ARP reply */
90efcacb
 
81d882d5
     uint8_t mac_src[OPENVPN_ETH_ALEN];
     in_addr_t ip_src;
     uint8_t mac_dest[OPENVPN_ETH_ALEN];
     in_addr_t ip_dest;
90efcacb
 };
 
6fbf66fa
 struct openvpn_iphdr {
81d882d5
 #define OPENVPN_IPH_GET_VER(v) (((v) >> 4) & 0x0F)
 #define OPENVPN_IPH_GET_LEN(v) (((v) & 0x0F) << 2)
     uint8_t version_len;
6fbf66fa
 
81d882d5
     uint8_t tos;
     uint16_t tot_len;
     uint16_t id;
6fbf66fa
 
81d882d5
 #define OPENVPN_IP_OFFMASK 0x1fff
     uint16_t frag_off;
6fbf66fa
 
81d882d5
     uint8_t ttl;
6fbf66fa
 
e11d2d14
 #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 */
81d882d5
     uint8_t protocol;
6fbf66fa
 
81d882d5
     uint16_t check;
     uint32_t saddr;
     uint32_t daddr;
     /*The options start here. */
6fbf66fa
 };
 
 /*
512cda46
  * IPv6 header
  */
 struct openvpn_ipv6hdr {
81d882d5
     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;
512cda46
 };
 
e11d2d14
 /*
  * 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];
 };
512cda46
 
 /*
6fbf66fa
  * UDP header
  */
 struct openvpn_udphdr {
81d882d5
     uint16_t source;
     uint16_t dest;
     uint16_t len;
     uint16_t check;
6fbf66fa
 };
 
 /*
  * TCP header, per RFC 793.
  */
 struct openvpn_tcphdr {
81d882d5
     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;
6fbf66fa
 };
 
81d882d5
 #define OPENVPN_TCPOPT_EOL     0
 #define OPENVPN_TCPOPT_NOP     1
 #define OPENVPN_TCPOPT_MAXSEG  2
6fbf66fa
 #define OPENVPN_TCPOLEN_MAXSEG 4
 
581bef87
 struct ip_tcp_udp_hdr {
81d882d5
     struct openvpn_iphdr ip;
     union {
         struct openvpn_tcphdr tcp;
         struct openvpn_udphdr udp;
     } u;
581bef87
 };
 
90efcacb
 #pragma pack()
 
6fbf66fa
 /*
  * 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) { \
81d882d5
         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; \
         } \
6fbf66fa
 }
 
581bef87
 #define ADD_CHECKSUM_32(acc, u32) { \
81d882d5
         acc += (u32) & 0xffff; \
         acc += (u32) >> 16;    \
581bef87
 }
 
 #define SUB_CHECKSUM_32(acc, u32) { \
81d882d5
         acc -= (u32) & 0xffff; \
         acc -= (u32) >> 16;    \
581bef87
 }
 
6fbf66fa
 /*
  * 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) \
81d882d5
                          - sizeof(struct openvpn_tcphdr))
6fbf66fa
 
 /*
e8c42658
  * This returns an ip protocol version of packet inside tun
  * and offset of IP header (via parameter).
  */
81d882d5
 inline static int
 get_tun_ip_ver(int tunnel_type, struct buffer *buf, int *ip_hdr_offset)
e8c42658
 {
81d882d5
     int ip_ver = -1;
e8c42658
 
81d882d5
     /* for tun get ip version from ip header */
     if (tunnel_type == DEV_TYPE_TUN)
e8c42658
     {
81d882d5
         *ip_hdr_offset = 0;
         if (likely(BLEN(buf) >= (int) sizeof(struct openvpn_iphdr)))
         {
             ip_ver = OPENVPN_IPH_GET_VER(*BPTR(buf));
         }
e8c42658
     }
81d882d5
     else if (tunnel_type == DEV_TYPE_TAP)
e8c42658
     {
81d882d5
         *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;
             }
         }
e8c42658
     }
 
81d882d5
     return ip_ver;
e8c42658
 }
 
 /*
f0e8997a
  * If raw tunnel packet is IPv4 or IPv6, return true and increment
6fbf66fa
  * buffer offset to start of IP header.
  */
81d882d5
 bool is_ipv4(int tunnel_type, struct buffer *buf);
 
 bool is_ipv6(int tunnel_type, struct buffer *buf);
6fbf66fa
 
e11d2d14
 /**
  *  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);
 
3c7f2f55
 #ifdef PACKET_TRUNCATION_CHECK
81d882d5
 void ipv4_packet_size_verify(const uint8_t *data,
                              const int size,
                              const int tunnel_type,
                              const char
                              *prefix,
                              counter_type *errors);
3c7f2f55
 
6fbf66fa
 #endif
81d882d5
 
 #endif /* ifndef PROTO_H */