aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/decode-icmpv6.h
blob: af97500607f88356b3570e686ae31c9fb3c300a5 (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
/* Copyright (C) 2007-2010 Open Information Security Foundation
 *
 * You can copy, redistribute or modify this Program 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
 * version 2 along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

/**
 * \file
 *
 * \author Victor Julien <victor@inliniac.net>
 */

#ifndef __DECODE_ICMPV6_H__
#define __DECODE_ICMPV6_H__

#include "decode-tcp.h"
#include "decode-sctp.h"
#include "decode-udp.h"
#include "decode-ipv6.h"

#define ICMPV6_HEADER_LEN       8
#define ICMPV6_HEADER_PKT_OFFSET 8

/** ICMPV6 Message Types: */
/** Error Messages: (type <128) */
#define ICMP6_DST_UNREACH             1
#define ICMP6_PACKET_TOO_BIG          2
#define ICMP6_TIME_EXCEEDED           3
#define ICMP6_PARAM_PROB              4

/** Informational Messages (type>=128) */
#define ICMP6_ECHO_REQUEST          128
#define ICMP6_ECHO_REPLY            129

#define MLD_LISTENER_QUERY          130
#define MLD_LISTENER_REPORT         131
#define MLD_LISTENER_REDUCTION      132

#define ND_ROUTER_SOLICIT           133
#define ND_ROUTER_ADVERT            134
#define ND_NEIGHBOR_SOLICIT         135
#define ND_NEIGHBOR_ADVERT          136
#define ND_REDIRECT                 137

/** Destination Unreachable Message (type=1) Code: */

#define ICMP6_DST_UNREACH_NOROUTE       0 /* no route to destination */
#define ICMP6_DST_UNREACH_ADMIN         1 /* communication with destination */
                                          /* administratively prohibited */
#define ICMP6_DST_UNREACH_BEYONDSCOPE   2 /* beyond scope of source address */
#define ICMP6_DST_UNREACH_ADDR          3 /* address unreachable */
#define ICMP6_DST_UNREACH_NOPORT        4 /* bad port */
#define ICMP6_DST_UNREACH_FAILEDPOLICY  5 /* Source address failed ingress/egress policy */
#define ICMP6_DST_UNREACH_REJECTROUTE   6 /* Reject route to destination */


/** Time Exceeded Message (type=3) Code: */
#define ICMP6_TIME_EXCEED_TRANSIT     0 /* Hop Limit == 0 in transit */
#define ICMP6_TIME_EXCEED_REASSEMBLY  1 /* Reassembly time out */

/** Parameter Problem Message (type=4) Code: */
#define ICMP6_PARAMPROB_HEADER        0 /* erroneous header field */
#define ICMP6_PARAMPROB_NEXTHEADER    1 /* unrecognized Next Header */
#define ICMP6_PARAMPROB_OPTION        2 /* unrecognized IPv6 option */


/** macro for icmpv6 "type" access */
#define ICMPV6_GET_TYPE(p)      (p)->icmpv6h->type
/** macro for icmpv6 "code" access */
#define ICMPV6_GET_CODE(p)      (p)->icmpv6h->code
/** macro for icmpv6 "csum" access */
#define ICMPV6_GET_CSUM(p)      (p)->icmpv6h->csum

/** If message is informational */
/** macro for icmpv6 "id" access */
#define ICMPV6_GET_ID(p)        (p)->icmpv6vars.id
/** macro for icmpv6 "seq" access */
#define ICMPV6_GET_SEQ(p)       (p)->icmpv6vars.seq

/** If message is Error */
/** macro for icmpv6 "unused" access */
#define ICMPV6_GET_UNUSED(p)       (p)->icmpv6h->icmpv6b.icmpv6e.unused
/** macro for icmpv6 "error_ptr" access */
#define ICMPV6_GET_ERROR_PTR(p)    (p)->icmpv6h->icmpv6b.icmpv6e.error_ptr
/** macro for icmpv6 "mtu" access */
#define ICMPV6_GET_MTU(p)          (p)->icmpv6h->icmpv6b.icmpv6e.mtu

/** macro for icmpv6 embedded "protocol" access */
#define ICMPV6_GET_EMB_PROTO(p)    (p)->icmpv6vars.emb_ip6_proto_next
/** macro for icmpv6 embedded "ipv6h" header access */
#define ICMPV6_GET_EMB_IPV6(p)     (p)->icmpv6vars.emb_ipv6h
/** macro for icmpv6 embedded "tcph" header access */
#define ICMPV6_GET_EMB_TCP(p)      (p)->icmpv6vars.emb_tcph
/** macro for icmpv6 embedded "udph" header access */
#define ICMPV6_GET_EMB_UDP(p)      (p)->icmpv6vars.emb_udph
/** macro for icmpv6 embedded "icmpv6h" header access */
#define ICMPV6_GET_EMB_icmpv6h(p)  (p)->icmpv6vars.emb_icmpv6h

typedef struct ICMPV6Info_
{
    uint16_t  id;
    uint16_t  seq;
} ICMPV6Info;

/** ICMPv6 header structure */
typedef struct ICMPV6Hdr_
{
    uint8_t  type;
    uint8_t  code;
    uint16_t csum;

    union {
        ICMPV6Info icmpv6i; /** Informational message */
        union
        {
            uint32_t  unused; /** for types 1 and 3, should be zero */
            uint32_t  error_ptr; /** for type 4, pointer to the octet that originate the error */
            uint32_t  mtu; /** for type 2, the Maximum Transmission Unit of the next-hop link */
        } icmpv6e;   /** Error Message */
    } icmpv6b;
} ICMPV6Hdr;

/** Data available from the decoded packet */
typedef struct ICMPV6Vars_ {
    /* checksum of the icmpv6 packet */
    uint16_t  id;
    uint16_t  seq;
    uint32_t  mtu;
    uint32_t  error_ptr;

    /** Pointers to the embedded packet headers */
    IPV6Hdr *emb_ipv6h;
    TCPHdr *emb_tcph;
    UDPHdr *emb_udph;
    ICMPV6Hdr *emb_icmpv6h;

    /** IPv6 src and dst address */
    uint32_t emb_ip6_src[4];
    uint32_t emb_ip6_dst[4];
    uint8_t emb_ip6_proto_next;

    /** TCP/UDP ports */
    uint16_t emb_sport;
    uint16_t emb_dport;

} ICMPV6Vars;


#define CLEAR_ICMPV6_PACKET(p) do { \
    (p)->level4_comp_csum = -1; \
    (p)->icmpv6vars.id = 0; \
    (p)->icmpv6vars.seq = 0; \
    (p)->icmpv6vars.mtu = 0; \
    (p)->icmpv6vars.error_ptr = 0; \
    (p)->icmpv6vars.emb_ipv6h = NULL; \
    (p)->icmpv6vars.emb_tcph = NULL; \
    (p)->icmpv6vars.emb_udph = NULL; \
    (p)->icmpv6vars.emb_icmpv6h = NULL; \
    (p)->icmpv6vars.emb_ip6_src[0] = 0; \
    (p)->icmpv6vars.emb_ip6_src[1] = 0; \
    (p)->icmpv6vars.emb_ip6_src[2] = 0; \
    (p)->icmpv6vars.emb_ip6_src[3] = 0; \
    (p)->icmpv6vars.emb_ip6_proto_next = 0; \
    (p)->icmpv6vars.emb_sport = 0; \
    (p)->icmpv6vars.emb_dport = 0; \
    (p)->icmpv6h = NULL; \
} while(0)

void DecodeICMPV6RegisterTests(void);

/** -------- Inline functions --------- */
static inline uint16_t ICMPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t);

/**
 * \brief Calculates the checksum for the ICMPV6 packet
 *
 * \param shdr Pointer to source address field from the IPV6 packet.  Used as a
 *             part of the psuedoheader for computing the checksum
 * \param pkt  Pointer to the start of the ICMPV6 packet
 * \param tlen Total length of the ICMPV6 packet(header + payload)
 *
 * \retval csum Checksum for the ICMPV6 packet
 */
static inline uint16_t ICMPV6CalculateChecksum(uint16_t *shdr, uint16_t *pkt,
                                        uint16_t tlen)
{
    uint16_t pad = 0;
    uint32_t csum = shdr[0];

    csum += shdr[1] + shdr[2] + shdr[3] + shdr[4] + shdr[5] + shdr[6] +
        shdr[7] + shdr[8] + shdr[9] + shdr[10] + shdr[11] + shdr[12] +
        shdr[13] + shdr[14] + shdr[15] + htons(58 + tlen);

    csum += pkt[0];

    tlen -= 4;
    pkt += 2;

    while (tlen >= 64) {
        csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
            pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
            pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19] +
            pkt[20] + pkt[21] + pkt[22] + pkt[23] + pkt[24] + pkt[25] +
            pkt[26] + pkt[27] + pkt[28] + pkt[29] + pkt[30] + pkt[31];
        tlen -= 64;
        pkt += 32;
    }

    while (tlen >= 32) {
        csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
            pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
            pkt[14] + pkt[15];
        tlen -= 32;
        pkt += 16;
    }

    while(tlen >= 8) {
        csum += pkt[0] + pkt[1] + pkt[2] + pkt[3];
        tlen -= 8;
        pkt += 4;
    }

    while(tlen >= 4) {
        csum += pkt[0] + pkt[1];
        tlen -= 4;
        pkt += 2;
    }

    while (tlen > 1) {
        csum += pkt[0];
        tlen -= 2;
        pkt += 1;
    }

    if (tlen == 1) {
        *(uint8_t *)(&pad) = (*(uint8_t *)pkt);
        csum += pad;
    }

    csum = (csum >> 16) + (csum & 0x0000FFFF);
    csum += (csum >> 16);

    return (uint16_t) ~csum;
}


#endif /* __DECODE_ICMPV6_H__ */