198404bec2acf0f1cac8084a6d2a9383042b6a97
[oonf.git] / src / nhdp / nhdpcheck / nhdpcheck.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include <oonf/libcommon/autobuf.h>
47 #include <oonf/oonf.h>
48
49 #include <oonf/libcore/oonf_logging.h>
50 #include <oonf/libcore/oonf_subsystem.h>
51 #include <oonf/subsystems/oonf_rfc5444.h>
52
53 #include <oonf/nhdp/nhdp/nhdp_interfaces.h>
54
55 #include <oonf/nhdp/nhdpcheck/nhdpcheck.h>
56
57 /* Definitions */
58 #define LOG_NHDPCHECK _olsrv2_nhdpcheck_subsystem.logging
59
60 /* prototypes */
61 static int _init(void);
62 static void _cleanup(void);
63
64 /* plugin declaration */
65 static const char *_dependencies[] = {
66   OONF_RFC5444_SUBSYSTEM,
67   OONF_NHDP_SUBSYSTEM,
68 };
69 static struct oonf_subsystem _olsrv2_nhdpcheck_subsystem = {
70   .name = OONF_NHDPCHECK_SUBSYSTEM,
71   .dependencies = _dependencies,
72   .dependencies_count = ARRAYSIZE(_dependencies),
73   .descr = "OLSRv2 nhdpcheck plugin",
74   .author = "Henning Rogge",
75
76   .init = _init,
77   .cleanup = _cleanup,
78 };
79 DECLARE_OONF_PLUGIN(_olsrv2_nhdpcheck_subsystem);
80
81 /* NHDP message TLV array index */
82 enum
83 {
84   IDX_TLV_ITIME,
85   IDX_TLV_VTIME,
86 };
87
88 /* NHDP address TLV array index pass 1 */
89 enum
90 {
91   IDX_ADDRTLV_LOCAL_IF,
92   IDX_ADDRTLV_LINK_STATUS,
93   IDX_ADDRTLV_OTHER_NEIGHB,
94 };
95
96 /* prototypes */
97 static enum rfc5444_result _cb_message_start_callback(struct rfc5444_reader_tlvblock_context *context);
98 static enum rfc5444_result _cb_messagetlvs(struct rfc5444_reader_tlvblock_context *context);
99 static enum rfc5444_result _cb_addresstlvs(struct rfc5444_reader_tlvblock_context *context);
100
101 /* definition of the RFC5444 reader components */
102 static struct rfc5444_reader_tlvblock_consumer _nhdp_message_consumer = {
103   .order = RFC5444_VALIDATOR_PRIORITY,
104   .msg_id = RFC6130_MSGTYPE_HELLO,
105   .start_callback = _cb_message_start_callback,
106   .block_callback = _cb_messagetlvs,
107 };
108
109 static struct rfc5444_reader_tlvblock_consumer_entry _nhdp_message_tlvs[] = {
110   [IDX_TLV_ITIME] = { .type = RFC5497_MSGTLV_INTERVAL_TIME },
111   [IDX_TLV_VTIME] = { .type = RFC5497_MSGTLV_VALIDITY_TIME },
112 };
113
114 static struct rfc5444_reader_tlvblock_consumer _nhdp_address_consumer = {
115   .order = RFC5444_VALIDATOR_PRIORITY,
116   .msg_id = RFC6130_MSGTYPE_HELLO,
117   .block_callback = _cb_addresstlvs,
118 };
119
120 static struct rfc5444_reader_tlvblock_consumer_entry _nhdp_address_tlvs[] = {
121   [IDX_ADDRTLV_LOCAL_IF] = { .type = RFC6130_ADDRTLV_LOCAL_IF },
122   [IDX_ADDRTLV_LINK_STATUS] = { .type = RFC6130_ADDRTLV_LINK_STATUS },
123   [IDX_ADDRTLV_OTHER_NEIGHB] = { .type = RFC6130_ADDRTLV_OTHER_NEIGHB },
124 };
125
126 /* nhdp multiplexer/protocol */
127 static struct oonf_rfc5444_protocol *_protocol = NULL;
128
129 /**
130  * Initialize plugin
131  * @return always returns 0 (cannot fail)
132  */
133 static int
134 _init(void) {
135   _protocol = oonf_rfc5444_get_default_protocol();
136   if (_protocol == NULL) {
137     return -1;
138   }
139
140   rfc5444_reader_add_message_consumer(
141     &_protocol->reader, &_nhdp_message_consumer, _nhdp_message_tlvs, ARRAYSIZE(_nhdp_message_tlvs));
142   rfc5444_reader_add_message_consumer(
143     &_protocol->reader, &_nhdp_address_consumer, _nhdp_address_tlvs, ARRAYSIZE(_nhdp_address_tlvs));
144
145   return 0;
146 }
147
148 /**
149  * Cleanup plugin
150  */
151 static void
152 _cleanup(void) {
153   rfc5444_reader_remove_message_consumer(&_protocol->reader, &_nhdp_message_consumer);
154   rfc5444_reader_remove_message_consumer(&_protocol->reader, &_nhdp_address_consumer);
155   _protocol = NULL;
156 }
157
158 /**
159  * Callback triggered when a NHDP hello message is received by the stack
160  * @param context rfc5444 tlvblock reader context
161  * @return see rfc5444_result enum
162  */
163 static enum rfc5444_result
164 _cb_message_start_callback(struct rfc5444_reader_tlvblock_context *context) {
165 #ifdef OONF_LOG_INFO
166   struct nhdp_interface *interf;
167
168   interf = nhdp_interface_get(_protocol->input.interface->name);
169   OONF_ASSERT(interf, LOG_NHDPCHECK, "Could not find NHDP interface %s", _protocol->input.interface->name);
170 #endif
171
172   /* check address length */
173   if (context->addr_len != 4 && context->addr_len != 16) {
174     OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message with addrlen %d on interface %s", context->addr_len,
175       nhdp_interface_get_name(interf));
176     return RFC5444_DROP_MESSAGE;
177   }
178
179   /* drop if message has hoplimit and its not 1 */
180   if (context->has_hoplimit && context->hoplimit != 1) {
181     OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message with hoplimit %d", context->hoplimit);
182     return RFC5444_DROP_MESSAGE;
183   }
184
185   /* drop if message has hopcount and its not 0 */
186   if (context->has_hopcount && context->hopcount != 0) {
187     OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message with hopcount %d", context->hopcount);
188     return RFC5444_DROP_MESSAGE;
189   }
190
191   return RFC5444_OKAY;
192 }
193
194 /**
195  * Callblack triggered to deliver the message TLVs received in a NHDP Hello
196  * @param context rfc5444 tlvblock reader context
197  * @return see rfc5444_result enum
198  */
199 static enum rfc5444_result
200 _cb_messagetlvs(struct rfc5444_reader_tlvblock_context *context __attribute__((unused))) {
201   /* drop message if it has no VTIME TLV or has more than one */
202   if (_nhdp_message_tlvs[IDX_TLV_VTIME].tlv == NULL || _nhdp_message_tlvs[IDX_TLV_VTIME].tlv->next_entry != NULL) {
203     OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message with no or multiple VTIME TLVs");
204     return RFC5444_DROP_MESSAGE;
205   }
206
207   /* check if VTIME TLV has length 1 */
208   if (_nhdp_message_tlvs[IDX_TLV_VTIME].tlv->length != 1) {
209     OONF_INFO(
210       LOG_NHDPCHECK, "Dropped NHDP message with VTIME TLV length %d", _nhdp_message_tlvs[IDX_TLV_VTIME].tlv->length);
211     return RFC5444_DROP_MESSAGE;
212   }
213
214   if (_nhdp_message_tlvs[IDX_TLV_ITIME].tlv) {
215     /* check if message has multiple ITIME TLVs */
216     if (_nhdp_message_tlvs[IDX_TLV_ITIME].tlv->next_entry != NULL) {
217       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message with multiple ITIME TLVs");
218       return RFC5444_DROP_MESSAGE;
219     }
220     if (_nhdp_message_tlvs[IDX_TLV_ITIME].tlv->length != 1) {
221       OONF_INFO(
222         LOG_NHDPCHECK, "Dropped NHDP message with ITIME TLV length %d", _nhdp_message_tlvs[IDX_TLV_ITIME].tlv->length);
223       return RFC5444_DROP_MESSAGE;
224     }
225
226     if (_nhdp_message_tlvs[IDX_TLV_ITIME].tlv->single_value[0] >
227         _nhdp_message_tlvs[IDX_TLV_VTIME].tlv->single_value[0]) {
228       OONF_INFO(LOG_NHDPCHECK,
229         "Dropped NHDP message because ITIME 0x%02x is larger"
230         "than VTIME 0x%02x",
231         _nhdp_message_tlvs[IDX_TLV_ITIME].tlv->single_value[0], _nhdp_message_tlvs[IDX_TLV_VTIME].tlv->single_value[0]);
232       return RFC5444_DROP_MESSAGE;
233     }
234   }
235   return RFC5444_OKAY;
236 }
237
238 /**
239  * Callblack triggered to deliver the address TLVs received in a NHDP Hello
240  * @param context rfc5444 tlvblock reader context
241  * @return see rfc5444_result enum
242  */
243
244 static enum rfc5444_result
245 _cb_addresstlvs(struct rfc5444_reader_tlvblock_context *context __attribute__((unused))) {
246 #ifdef OONF_LOG_INFO
247   struct netaddr_str buf;
248 #endif
249
250   if (_nhdp_address_tlvs[IDX_ADDRTLV_LOCAL_IF].tlv != NULL) {
251     /* check for duplicate LOCAL_IF TLV */
252     if (_nhdp_address_tlvs[IDX_ADDRTLV_LOCAL_IF].tlv->next_entry != NULL) {
253       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had multiple LOCAL_IF TLVs", buf.buf);
254       return RFC5444_DROP_MESSAGE;
255     }
256
257     /* check for bad length of LOCAL_IF TLV */
258     if (_nhdp_address_tlvs[IDX_ADDRTLV_LOCAL_IF].tlv->length != 1) {
259       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had LOCAL_IF TLV length %d", buf.buf,
260         _nhdp_address_tlvs[IDX_ADDRTLV_LOCAL_IF].tlv->length);
261       return RFC5444_DROP_MESSAGE;
262     }
263
264     /* check if address had both LOCAL_IF and LINK_STATUS TLV */
265     if (_nhdp_address_tlvs[IDX_ADDRTLV_LINK_STATUS].tlv != NULL) {
266       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had LOCAL_IF and LINK_STATUS TLV", buf.buf);
267       return RFC5444_DROP_MESSAGE;
268     }
269
270     /* check if address had both LOCAL_IF and OTHER_NEIGH TLV */
271     if (_nhdp_address_tlvs[IDX_ADDRTLV_OTHER_NEIGHB].tlv != NULL) {
272       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had LOCAL_IF and OTHER_NEIGHB TLV", buf.buf);
273       return RFC5444_DROP_MESSAGE;
274     }
275   }
276
277   if (_nhdp_address_tlvs[IDX_ADDRTLV_LINK_STATUS].tlv != NULL) {
278     /* check for duplicate LINK_STATUS TLV */
279     if (_nhdp_address_tlvs[IDX_ADDRTLV_LINK_STATUS].tlv->next_entry != NULL) {
280       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had multiple LINK_STATUS TLVs", buf.buf);
281       return RFC5444_DROP_MESSAGE;
282     }
283
284     /* check for bad length of LINK_STATUS TLV */
285     if (_nhdp_address_tlvs[IDX_ADDRTLV_LINK_STATUS].tlv->length != 1) {
286       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had LINK_STATUS TLV length %d", buf.buf,
287         _nhdp_address_tlvs[IDX_ADDRTLV_LINK_STATUS].tlv->length);
288       return RFC5444_DROP_MESSAGE;
289     }
290   }
291
292   if (_nhdp_address_tlvs[IDX_ADDRTLV_OTHER_NEIGHB].tlv != NULL) {
293     /* check for duplicate OTHER_NEIGH TLV */
294     if (_nhdp_address_tlvs[IDX_ADDRTLV_OTHER_NEIGHB].tlv->next_entry != NULL) {
295       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had multiple OTHER_NEIGHB TLVs", buf.buf);
296       return RFC5444_DROP_MESSAGE;
297     }
298
299     /* check for bad length of OTHER_NEIGH TLV */
300     if (_nhdp_address_tlvs[IDX_ADDRTLV_OTHER_NEIGHB].tlv->length != 1) {
301       OONF_INFO(LOG_NHDPCHECK, "Dropped NHDP message, address %s had OTHER_NEIGH TLV length %d", buf.buf,
302         _nhdp_address_tlvs[IDX_ADDRTLV_OTHER_NEIGHB].tlv->length);
303       return RFC5444_DROP_MESSAGE;
304     }
305   }
306
307   return RFC5444_OKAY;
308 }