|
1 The following patches are pulled directly from the GIT repository |
|
2 for the quagga community. They fix the following CVEs: |
|
3 |
|
4 CVE-2012-0249 |
|
5 CVE-2012-0250 |
|
6 CVE-2012-0255 |
|
7 |
|
8 All of the patched CVEs are included in Quagga 0.99.20.1. This patch |
|
9 file can be removed if Quagga is upgraded to that version. |
|
10 |
|
11 |
|
12 |
|
13 From 5861739f8c38bc36ea9955e5cb2be2bf2f482d70 Mon Sep 17 00:00:00 2001 |
|
14 From: Paul Jakma <[email protected]> |
|
15 Date: Mon, 09 Jan 2012 20:59:26 +0000 |
|
16 Subject: bgpd: Open option parse errors don't NOTIFY, resulting in abort & DoS |
|
17 |
|
18 * bgp_packet.c: (bgp_open_receive) Errors from bgp_open_option_parse are |
|
19 detected, and the code will stop processing the OPEN and return. However |
|
20 it does so without calling bgp_notify_send to send a NOTIFY - which means |
|
21 the peer FSM doesn't get stopped, and bgp_read will be called again later. |
|
22 Because it returns, it doesn't go through the code near the end of the |
|
23 function that removes the current message from the peer input streaam. |
|
24 Thus the next call to bgp_read will try to parse a half-parsed stream as |
|
25 if it were a new BGP message, leading to an assert later in the code when |
|
26 it tries to read stuff that isn't there. Add the required call to |
|
27 bgp_notify_send before returning. |
|
28 * bgp_open.c: (bgp_capability_as4) Be a bit stricter, check the length field |
|
29 corresponds to the only value it can be, which is the amount we're going to |
|
30 read off the stream. And make sure the capability flag gets set, so |
|
31 callers can know this capability was read, regardless. |
|
32 (peek_for_as4_capability) Let bgp_capability_as4 do the length check. |
|
33 --- |
|
34 diff --git bgpd/bgp_open.c bgpd/bgp_open.c |
|
35 index 82deb3d..b5b50bb 100644 |
|
36 --- bgpd/bgp_open.c |
|
37 +++ bgpd/bgp_open.c |
|
38 @@ -421,13 +421,20 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) |
|
39 static as_t |
|
40 bgp_capability_as4 (struct peer *peer, struct capability_header *hdr) |
|
41 { |
|
42 + SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); |
|
43 + |
|
44 + if (hdr->length != CAPABILITY_CODE_AS4_LEN) |
|
45 + { |
|
46 + zlog_err ("%s AS4 capability has incorrect data length %d", |
|
47 + peer->host, hdr->length); |
|
48 + return 0; |
|
49 + } |
|
50 + |
|
51 as_t as4 = stream_getl (BGP_INPUT(peer)); |
|
52 |
|
53 if (BGP_DEBUG (as4, AS4)) |
|
54 zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", |
|
55 peer->host, as4); |
|
56 - SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); |
|
57 - |
|
58 return as4; |
|
59 } |
|
60 |
|
61 @@ -689,9 +696,6 @@ peek_for_as4_capability (struct peer *peer, u_char length) |
|
62 |
|
63 if (hdr.code == CAPABILITY_CODE_AS4) |
|
64 { |
|
65 - if (hdr.length != CAPABILITY_CODE_AS4_LEN) |
|
66 - goto end; |
|
67 - |
|
68 if (BGP_DEBUG (as4, AS4)) |
|
69 zlog_info ("[AS4] found AS4 capability, about to parse"); |
|
70 as4 = bgp_capability_as4 (peer, &hdr); |
|
71 diff --git bgpd/bgp_packet.c bgpd/bgp_packet.c |
|
72 index f5a74d1..5d8087a 100644 |
|
73 --- bgpd/bgp_packet.c |
|
74 +++ bgpd/bgp_packet.c |
|
75 @@ -1459,9 +1459,13 @@ bgp_open_receive (struct peer *peer, bgp_size_t size) |
|
76 /* Open option part parse. */ |
|
77 if (optlen != 0) |
|
78 { |
|
79 - ret = bgp_open_option_parse (peer, optlen, &capability); |
|
80 - if (ret < 0) |
|
81 - return ret; |
|
82 + if ((ret = bgp_open_option_parse (peer, optlen, &capability)) < 0) |
|
83 + { |
|
84 + bgp_notify_send (peer, |
|
85 + BGP_NOTIFY_OPEN_ERR, |
|
86 + BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); |
|
87 + return ret; |
|
88 + } |
|
89 } |
|
90 else |
|
91 { |
|
92 -- |
|
93 cgit v0.9.0.2 |
|
94 From 393b2d64dc0625ba8e01e9e1516efac06d13072e Mon Sep 17 00:00:00 2001 |
|
95 From: Denis Ovsienko <[email protected]> |
|
96 Date: Sun, 15 Jan 2012 15:12:19 +0000 |
|
97 Subject: ospfd: use LOOKUP() for ospf_packet_type_str |
|
98 |
|
99 * ospf_packet.h: add proper str/max extern declarations |
|
100 * ospf_packet.c |
|
101 * ospf_packet_type_str: rewrite in "struct message", add max value |
|
102 * ospf_packet_add(): use LOOKUP() |
|
103 * ospf_write(): ditto |
|
104 * ospf_hello(): ditto |
|
105 * ospf_read(): ditto |
|
106 * ospf_dump.h: the declaration does not belong here |
|
107 * ospf_dump.c |
|
108 * ospf_header_dump(): use LOOKUP() |
|
109 * show_debugging_ospf(): ditto |
|
110 --- |
|
111 diff --git ospfd/ospf_dump.c ospfd/ospf_dump.c |
|
112 index e65b2e3..8ace095 100644 |
|
113 --- ospfd/ospf_dump.c |
|
114 +++ ospfd/ospf_dump.c |
|
115 @@ -661,7 +661,7 @@ ospf_header_dump (struct ospf_header *ospfh) |
|
116 zlog_debug ("Header"); |
|
117 zlog_debug (" Version %d", ospfh->version); |
|
118 zlog_debug (" Type %d (%s)", ospfh->type, |
|
119 - ospf_packet_type_str[ospfh->type]); |
|
120 + LOOKUP (ospf_packet_type_str, ospfh->type)); |
|
121 zlog_debug (" Packet Len %d", ntohs (ospfh->length)); |
|
122 zlog_debug (" Router ID %s", inet_ntoa (ospfh->router_id)); |
|
123 zlog_debug (" Area ID %s", inet_ntoa (ospfh->area_id)); |
|
124 @@ -1457,7 +1457,7 @@ DEFUN (show_debugging_ospf, |
|
125 if (IS_DEBUG_OSPF_PACKET (i, SEND) && IS_DEBUG_OSPF_PACKET (i, RECV)) |
|
126 { |
|
127 vty_out (vty, " OSPF packet %s%s debugging is on%s", |
|
128 - ospf_packet_type_str[i + 1], |
|
129 + LOOKUP (ospf_packet_type_str, i + 1), |
|
130 IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", |
|
131 VTY_NEWLINE); |
|
132 } |
|
133 @@ -1465,12 +1465,12 @@ DEFUN (show_debugging_ospf, |
|
134 { |
|
135 if (IS_DEBUG_OSPF_PACKET (i, SEND)) |
|
136 vty_out (vty, " OSPF packet %s send%s debugging is on%s", |
|
137 - ospf_packet_type_str[i + 1], |
|
138 + LOOKUP (ospf_packet_type_str, i + 1), |
|
139 IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", |
|
140 VTY_NEWLINE); |
|
141 if (IS_DEBUG_OSPF_PACKET (i, RECV)) |
|
142 vty_out (vty, " OSPF packet %s receive%s debugging is on%s", |
|
143 - ospf_packet_type_str[i + 1], |
|
144 + LOOKUP (ospf_packet_type_str, i + 1), |
|
145 IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", |
|
146 VTY_NEWLINE); |
|
147 } |
|
148 diff --git ospfd/ospf_dump.h ospfd/ospf_dump.h |
|
149 index fb81371..455214f 100644 |
|
150 --- ospfd/ospf_dump.h |
|
151 +++ ospfd/ospf_dump.h |
|
152 @@ -121,7 +121,6 @@ extern unsigned long term_debug_ospf_zebra; |
|
153 extern unsigned long term_debug_ospf_nssa; |
|
154 |
|
155 /* Message Strings. */ |
|
156 -extern const char *ospf_packet_type_str[]; |
|
157 extern char *ospf_lsa_type_str[]; |
|
158 |
|
159 /* Prototypes. */ |
|
160 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
161 index 0f338d3..03e6d2a 100644 |
|
162 --- ospfd/ospf_packet.c |
|
163 +++ ospfd/ospf_packet.c |
|
164 @@ -50,15 +50,16 @@ |
|
165 #include "ospfd/ospf_dump.h" |
|
166 |
|
167 /* Packet Type String. */ |
|
168 -const char *ospf_packet_type_str[] = |
|
169 -{ |
|
170 - "unknown", |
|
171 - "Hello", |
|
172 - "Database Description", |
|
173 - "Link State Request", |
|
174 - "Link State Update", |
|
175 - "Link State Acknowledgment", |
|
176 +const struct message ospf_packet_type_str[] = |
|
177 +{ |
|
178 + { OSPF_MSG_HELLO, "Hello" }, |
|
179 + { OSPF_MSG_DB_DESC, "Database Description" }, |
|
180 + { OSPF_MSG_LS_REQ, "Link State Request" }, |
|
181 + { OSPF_MSG_LS_UPD, "Link State Update" }, |
|
182 + { OSPF_MSG_LS_ACK, "Link State Acknowledgment" }, |
|
183 }; |
|
184 +const size_t ospf_packet_type_str_max = sizeof (ospf_packet_type_str) / |
|
185 + sizeof (ospf_packet_type_str[0]); |
|
186 |
|
187 /* OSPF authentication checking function */ |
|
188 static int |
|
189 @@ -201,7 +202,7 @@ ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op) |
|
190 "destination %s) called with NULL obuf, ignoring " |
|
191 "(please report this bug)!\n", |
|
192 IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state), |
|
193 - ospf_packet_type_str[stream_getc_from(op->s, 1)], |
|
194 + LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)), |
|
195 inet_ntoa (op->dst)); |
|
196 return; |
|
197 } |
|
198 @@ -755,7 +756,7 @@ ospf_write (struct thread *thread) |
|
199 } |
|
200 |
|
201 zlog_debug ("%s sent to [%s] via [%s].", |
|
202 - ospf_packet_type_str[type], inet_ntoa (op->dst), |
|
203 + LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst), |
|
204 IF_NAME (oi)); |
|
205 |
|
206 if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) |
|
207 @@ -801,7 +802,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh, |
|
208 { |
|
209 zlog_debug ("ospf_header[%s/%s]: selforiginated, " |
|
210 "dropping.", |
|
211 - ospf_packet_type_str[ospfh->type], |
|
212 + LOOKUP (ospf_packet_type_str, ospfh->type), |
|
213 inet_ntoa (iph->ip_src)); |
|
214 } |
|
215 return; |
|
216 @@ -2571,7 +2572,7 @@ ospf_read (struct thread *thread) |
|
217 } |
|
218 |
|
219 zlog_debug ("%s received from [%s] via [%s]", |
|
220 - ospf_packet_type_str[ospfh->type], |
|
221 + LOOKUP (ospf_packet_type_str, ospfh->type), |
|
222 inet_ntoa (ospfh->router_id), IF_NAME (oi)); |
|
223 zlog_debug (" src [%s],", inet_ntoa (iph->ip_src)); |
|
224 zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst)); |
|
225 diff --git ospfd/ospf_packet.h ospfd/ospf_packet.h |
|
226 index 9a47208..2115f11 100644 |
|
227 --- ospfd/ospf_packet.h |
|
228 +++ ospfd/ospf_packet.h |
|
229 @@ -163,4 +163,7 @@ extern int ospf_ls_ack_timer (struct thread *); |
|
230 extern int ospf_poll_timer (struct thread *); |
|
231 extern int ospf_hello_reply_timer (struct thread *); |
|
232 |
|
233 +extern const struct message ospf_packet_type_str[]; |
|
234 +extern const size_t ospf_packet_type_str_max; |
|
235 + |
|
236 #endif /* _ZEBRA_OSPF_PACKET_H */ |
|
237 -- |
|
238 cgit v0.9.0.2 |
|
239 From 099ed6744881e71957f2bfeebc4c0727714d2394 Mon Sep 17 00:00:00 2001 |
|
240 From: Denis Ovsienko <[email protected]> |
|
241 Date: Fri, 20 Jan 2012 18:32:10 +0000 |
|
242 Subject: ospfd: fix ospf_packet_add_top() to use LOOKUP() |
|
243 |
|
244 --- |
|
245 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
246 index 03e6d2a..500f245 100644 |
|
247 --- ospfd/ospf_packet.c |
|
248 +++ ospfd/ospf_packet.c |
|
249 @@ -223,7 +223,7 @@ ospf_packet_add_top (struct ospf_interface *oi, struct ospf_packet *op) |
|
250 "destination %s) called with NULL obuf, ignoring " |
|
251 "(please report this bug)!\n", |
|
252 IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state), |
|
253 - ospf_packet_type_str[stream_getc_from(op->s, 1)], |
|
254 + LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)), |
|
255 inet_ntoa (op->dst)); |
|
256 return; |
|
257 } |
|
258 -- |
|
259 cgit v0.9.0.2 |
|
260 From 3092cd57fb44c8293995d013bd86937d1a91745f Mon Sep 17 00:00:00 2001 |
|
261 From: Denis Ovsienko <[email protected]> |
|
262 Date: Mon, 30 Jan 2012 11:41:39 +0000 |
|
263 Subject: ospfd: introduce ospf_packet_minlen[] (BZ#705) |
|
264 |
|
265 This commit ports some of the OSPFv3 packet reception checks |
|
266 to OSPFv2. |
|
267 |
|
268 * ospf_packet.c |
|
269 * ospf_packet_minlen[]: a direct equivalent of ospf6_packet_minlen[] |
|
270 * ospf_packet_examin(): new function designed after the first part |
|
271 of ospf6_packet_examin() |
|
272 * ospf_read(): verify received packet with ospf_packet_examin() |
|
273 * ospf_packet.h: add convenience macros |
|
274 --- |
|
275 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
276 index 500f245..f425da8 100644 |
|
277 --- ospfd/ospf_packet.c |
|
278 +++ ospfd/ospf_packet.c |
|
279 @@ -61,6 +61,18 @@ const struct message ospf_packet_type_str[] = |
|
280 const size_t ospf_packet_type_str_max = sizeof (ospf_packet_type_str) / |
|
281 sizeof (ospf_packet_type_str[0]); |
|
282 |
|
283 +/* Minimum (besides OSPF_HEADER_SIZE) lengths for OSPF packets of |
|
284 + particular types, offset is the "type" field of a packet. */ |
|
285 +static const u_int16_t ospf_packet_minlen[] = |
|
286 +{ |
|
287 + 0, |
|
288 + OSPF_HELLO_MIN_SIZE, |
|
289 + OSPF_DB_DESC_MIN_SIZE, |
|
290 + OSPF_LS_REQ_MIN_SIZE, |
|
291 + OSPF_LS_UPD_MIN_SIZE, |
|
292 + OSPF_LS_ACK_MIN_SIZE, |
|
293 +}; |
|
294 + |
|
295 /* OSPF authentication checking function */ |
|
296 static int |
|
297 ospf_auth_type (struct ospf_interface *oi) |
|
298 @@ -2309,6 +2321,47 @@ ospf_check_sum (struct ospf_header *ospfh) |
|
299 return 1; |
|
300 } |
|
301 |
|
302 +/* Verify a complete OSPF packet for proper sizing/alignment. */ |
|
303 +static unsigned |
|
304 +ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
305 +{ |
|
306 + u_int16_t bytesdeclared; |
|
307 + |
|
308 + /* Length, 1st approximation. */ |
|
309 + if (bytesonwire < OSPF_HEADER_SIZE) |
|
310 + { |
|
311 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
312 + zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire); |
|
313 + return MSG_NG; |
|
314 + } |
|
315 + /* Now it is safe to access header fields. Performing length check, allow |
|
316 + * for possible extra bytes of crypto auth/padding, which are not counted |
|
317 + * in the OSPF header "length" field. */ |
|
318 + bytesdeclared = ntohs (oh->length); |
|
319 + if (bytesdeclared > bytesonwire) |
|
320 + { |
|
321 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
322 + zlog_debug ("%s: packet length error (%u real, %u declared)", |
|
323 + __func__, bytesonwire, bytesdeclared); |
|
324 + return MSG_NG; |
|
325 + } |
|
326 + /* Length, 2nd approximation. The type-specific constraint is checked |
|
327 + against declared length, not amount of bytes on wire. */ |
|
328 + if |
|
329 + ( |
|
330 + oh->type >= OSPF_MSG_HELLO && |
|
331 + oh->type <= OSPF_MSG_LS_ACK && |
|
332 + bytesdeclared < OSPF_HEADER_SIZE + ospf_packet_minlen[oh->type] |
|
333 + ) |
|
334 + { |
|
335 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
336 + zlog_debug ("%s: undersized (%u B) %s packet", __func__, |
|
337 + bytesdeclared, LOOKUP (ospf_packet_type_str, oh->type)); |
|
338 + return MSG_NG; |
|
339 + } |
|
340 + return MSG_OK; |
|
341 +} |
|
342 + |
|
343 /* OSPF Header verification. */ |
|
344 static int |
|
345 ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, |
|
346 @@ -2404,10 +2457,10 @@ ospf_read (struct thread *thread) |
|
347 /* prepare for next packet. */ |
|
348 ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd); |
|
349 |
|
350 - /* read OSPF packet. */ |
|
351 stream_reset(ospf->ibuf); |
|
352 if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf))) |
|
353 return -1; |
|
354 + /* This raw packet is known to be at least as big as its IP header. */ |
|
355 |
|
356 /* Note that there should not be alignment problems with this assignment |
|
357 because this is at the beginning of the stream data buffer. */ |
|
358 @@ -2442,16 +2495,10 @@ ospf_read (struct thread *thread) |
|
359 by ospf_recv_packet() to be correct). */ |
|
360 stream_forward_getp (ibuf, iph->ip_hl * 4); |
|
361 |
|
362 - /* Make sure the OSPF header is really there. */ |
|
363 - if (stream_get_endp (ibuf) - stream_get_getp (ibuf) < OSPF_HEADER_SIZE) |
|
364 - { |
|
365 - zlog_debug ("ospf_read: ignored OSPF packet with undersized (%u bytes) header", |
|
366 - stream_get_endp (ibuf) - stream_get_getp (ibuf)); |
|
367 + ospfh = (struct ospf_header *) STREAM_PNT (ibuf); |
|
368 + if (MSG_OK != ospf_packet_examin (ospfh, stream_get_endp (ibuf) - stream_get_getp (ibuf))) |
|
369 return -1; |
|
370 - } |
|
371 - |
|
372 /* Now it is safe to access all fields of OSPF packet header. */ |
|
373 - ospfh = (struct ospf_header *) STREAM_PNT (ibuf); |
|
374 |
|
375 /* associate packet with ospf interface */ |
|
376 oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp); |
|
377 diff --git ospfd/ospf_packet.h ospfd/ospf_packet.h |
|
378 index 2115f11..3cbe889 100644 |
|
379 --- ospfd/ospf_packet.h |
|
380 +++ ospfd/ospf_packet.h |
|
381 @@ -46,6 +46,10 @@ |
|
382 |
|
383 #define OSPF_HELLO_REPLY_DELAY 1 |
|
384 |
|
385 +/* Return values of functions involved in packet verification, see ospf6d. */ |
|
386 +#define MSG_OK 0 |
|
387 +#define MSG_NG 1 |
|
388 + |
|
389 struct ospf_packet |
|
390 { |
|
391 struct ospf_packet *next; |
|
392 -- |
|
393 cgit v0.9.0.2 |
|
394 From 3779a3bf9d27b3cccda7e45223884257af362c28 Mon Sep 17 00:00:00 2001 |
|
395 From: Denis Ovsienko <[email protected]> |
|
396 Date: Mon, 30 Jan 2012 12:07:18 +0000 |
|
397 Subject: ospfd: review ospf_check_auth() |
|
398 |
|
399 1. The only purpose of "ibuf" argument was to get stream size, which |
|
400 was always equal to OSPF_MAX_PACKET_SIZE + 1, exactly as initialized |
|
401 in ospf_new(). |
|
402 |
|
403 2. Fix the packet size check condition, which was incorrect for very |
|
404 large packets, at least in theory. |
|
405 --- |
|
406 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
407 index f425da8..a71cc99 100644 |
|
408 --- ospfd/ospf_packet.c |
|
409 +++ ospfd/ospf_packet.c |
|
410 @@ -2255,8 +2255,7 @@ ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src) |
|
411 } |
|
412 |
|
413 static int |
|
414 -ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf, |
|
415 - struct ospf_header *ospfh) |
|
416 +ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh) |
|
417 { |
|
418 int ret = 0; |
|
419 struct crypt_key *ck; |
|
420 @@ -2282,7 +2281,7 @@ ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf, |
|
421 /* This is very basic, the digest processing is elsewhere */ |
|
422 if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE && |
|
423 ospfh->u.crypt.key_id == ck->key_id && |
|
424 - ntohs (ospfh->length) + OSPF_AUTH_SIMPLE_SIZE <= stream_get_size (ibuf)) |
|
425 + ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE <= OSPF_MAX_PACKET_SIZE) |
|
426 ret = 1; |
|
427 else |
|
428 ret = 0; |
|
429 @@ -2406,7 +2405,7 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, |
|
430 return -1; |
|
431 } |
|
432 |
|
433 - if (! ospf_check_auth (oi, ibuf, ospfh)) |
|
434 + if (! ospf_check_auth (oi, ospfh)) |
|
435 { |
|
436 zlog_warn ("interface %s: ospf_read authentication failed.", |
|
437 IF_NAME (oi)); |
|
438 -- |
|
439 cgit v0.9.0.2 |
|
440 From 7edfc01207f3eee8f26d5c22cfef7c7f030c52ce Mon Sep 17 00:00:00 2001 |
|
441 From: Denis Ovsienko <[email protected]> |
|
442 Date: Mon, 30 Jan 2012 16:32:39 +0000 |
|
443 Subject: ospfd: review ospf_check_md5_digest() |
|
444 |
|
445 Rewrite some pointer arithmetics without the additional variables and |
|
446 move byte order conversion inside the function. |
|
447 --- |
|
448 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
449 index a71cc99..5704f9d 100644 |
|
450 --- ospfd/ospf_packet.c |
|
451 +++ ospfd/ospf_packet.c |
|
452 @@ -304,24 +304,14 @@ ospf_packet_max (struct ospf_interface *oi) |
|
453 |
|
454 |
|
455 static int |
|
456 -ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s, |
|
457 - u_int16_t length) |
|
458 +ospf_check_md5_digest (struct ospf_interface *oi, struct ospf_header *ospfh) |
|
459 { |
|
460 - unsigned char *ibuf; |
|
461 MD5_CTX ctx; |
|
462 unsigned char digest[OSPF_AUTH_MD5_SIZE]; |
|
463 - unsigned char *pdigest; |
|
464 struct crypt_key *ck; |
|
465 - struct ospf_header *ospfh; |
|
466 struct ospf_neighbor *nbr; |
|
467 + u_int16_t length = ntohs (ospfh->length); |
|
468 |
|
469 - |
|
470 - ibuf = STREAM_PNT (s); |
|
471 - ospfh = (struct ospf_header *) ibuf; |
|
472 - |
|
473 - /* Get pointer to the end of the packet. */ |
|
474 - pdigest = ibuf + length; |
|
475 - |
|
476 /* Get secret key. */ |
|
477 ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt), |
|
478 ospfh->u.crypt.key_id); |
|
479 @@ -347,12 +337,12 @@ ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s, |
|
480 /* Generate a digest for the ospf packet - their digest + our digest. */ |
|
481 memset(&ctx, 0, sizeof(ctx)); |
|
482 MD5Init(&ctx); |
|
483 - MD5Update(&ctx, ibuf, length); |
|
484 + MD5Update(&ctx, ospfh, length); |
|
485 MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE); |
|
486 MD5Final(digest, &ctx); |
|
487 |
|
488 /* compare the two */ |
|
489 - if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE)) |
|
490 + if (memcmp ((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) |
|
491 { |
|
492 zlog_warn ("interface %s: ospf_check_md5 checksum mismatch", |
|
493 IF_NAME (oi)); |
|
494 @@ -2426,7 +2416,7 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, |
|
495 { |
|
496 if (ospfh->checksum != 0) |
|
497 return -1; |
|
498 - if (ospf_check_md5_digest (oi, ibuf, ntohs (ospfh->length)) == 0) |
|
499 + if (ospf_check_md5_digest (oi, ospfh) == 0) |
|
500 { |
|
501 zlog_warn ("interface %s: ospf_read md5 authentication failed.", |
|
502 IF_NAME (oi)); |
|
503 -- |
|
504 cgit v0.9.0.2 |
|
505 From fba10fc38f482c617fdfbb81b8d855df56eeda51 Mon Sep 17 00:00:00 2001 |
|
506 From: Denis Ovsienko <[email protected]> |
|
507 Date: Fri, 17 Feb 2012 12:20:50 +0000 |
|
508 Subject: ospfd: introduce ospf_lsa_minlen[] (BZ#705) |
|
509 |
|
510 This commit ports more packet checks to OSPFv2, in particular, LSA size |
|
511 verification and Router-LSA link blocks verification. |
|
512 |
|
513 * ospf_lsa.h: add LSA size macros |
|
514 * ospf_packet.h: add struct ospf_ls_update |
|
515 * ospf_packet.c |
|
516 * ospf_lsa_minlen[]: a direct equivalent of ospf6_lsa_minlen[] |
|
517 * ospf_router_lsa_links_examin(): new function, verifies trailing |
|
518 part of a Router-LSA |
|
519 * ospf_lsa_examin(): new function like ospf6_lsa_examin() |
|
520 * ospf_lsaseq_examin(): new function like ospf6_lsaseq_examin() |
|
521 * ospf_packet_examin(): add type-specific deeper level checks |
|
522 --- |
|
523 diff --git ospfd/ospf_lsa.h ospfd/ospf_lsa.h |
|
524 index bf3b083..ca0653c 100644 |
|
525 --- ospfd/ospf_lsa.h |
|
526 +++ ospfd/ospf_lsa.h |
|
527 @@ -153,6 +153,7 @@ struct router_lsa_link |
|
528 }; |
|
529 |
|
530 /* OSPF Router-LSAs structure. */ |
|
531 +#define OSPF_ROUTER_LSA_MIN_SIZE 16U /* w/1 link descriptor */ |
|
532 struct router_lsa |
|
533 { |
|
534 struct lsa_header header; |
|
535 @@ -170,6 +171,7 @@ struct router_lsa |
|
536 }; |
|
537 |
|
538 /* OSPF Network-LSAs structure. */ |
|
539 +#define OSPF_NETWORK_LSA_MIN_SIZE 8U /* w/1 router-ID */ |
|
540 struct network_lsa |
|
541 { |
|
542 struct lsa_header header; |
|
543 @@ -178,6 +180,7 @@ struct network_lsa |
|
544 }; |
|
545 |
|
546 /* OSPF Summary-LSAs structure. */ |
|
547 +#define OSPF_SUMMARY_LSA_MIN_SIZE 8U /* w/1 TOS metric block */ |
|
548 struct summary_lsa |
|
549 { |
|
550 struct lsa_header header; |
|
551 @@ -187,6 +190,7 @@ struct summary_lsa |
|
552 }; |
|
553 |
|
554 /* OSPF AS-external-LSAs structure. */ |
|
555 +#define OSPF_AS_EXTERNAL_LSA_MIN_SIZE 16U /* w/1 TOS forwarding block */ |
|
556 struct as_external_lsa |
|
557 { |
|
558 struct lsa_header header; |
|
559 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
560 index 5704f9d..3b82820 100644 |
|
561 --- ospfd/ospf_packet.c |
|
562 +++ ospfd/ospf_packet.c |
|
563 @@ -73,6 +73,24 @@ static const u_int16_t ospf_packet_minlen[] = |
|
564 OSPF_LS_ACK_MIN_SIZE, |
|
565 }; |
|
566 |
|
567 +/* Minimum (besides OSPF_LSA_HEADER_SIZE) lengths for LSAs of particular |
|
568 + types, offset is the "LSA type" field. */ |
|
569 +static const u_int16_t ospf_lsa_minlen[] = |
|
570 +{ |
|
571 + 0, |
|
572 + OSPF_ROUTER_LSA_MIN_SIZE, |
|
573 + OSPF_NETWORK_LSA_MIN_SIZE, |
|
574 + OSPF_SUMMARY_LSA_MIN_SIZE, |
|
575 + OSPF_SUMMARY_LSA_MIN_SIZE, |
|
576 + OSPF_AS_EXTERNAL_LSA_MIN_SIZE, |
|
577 + 0, |
|
578 + OSPF_AS_EXTERNAL_LSA_MIN_SIZE, |
|
579 + 0, |
|
580 + 0, |
|
581 + 0, |
|
582 + 0, |
|
583 +}; |
|
584 + |
|
585 /* OSPF authentication checking function */ |
|
586 static int |
|
587 ospf_auth_type (struct ospf_interface *oi) |
|
588 @@ -2310,11 +2328,199 @@ ospf_check_sum (struct ospf_header *ospfh) |
|
589 return 1; |
|
590 } |
|
591 |
|
592 +/* Verify, that given link/TOS records are properly sized/aligned and match |
|
593 + Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */ |
|
594 +static unsigned |
|
595 +ospf_router_lsa_links_examin |
|
596 +( |
|
597 + struct router_lsa_link * link, |
|
598 + u_int16_t linkbytes, |
|
599 + const u_int16_t num_links |
|
600 +) |
|
601 +{ |
|
602 + unsigned counted_links = 0, thislinklen; |
|
603 + |
|
604 + while (linkbytes) |
|
605 + { |
|
606 + thislinklen = OSPF_ROUTER_LSA_LINK_SIZE + 4 * link->m[0].tos_count; |
|
607 + if (thislinklen > linkbytes) |
|
608 + { |
|
609 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
610 + zlog_debug ("%s: length error in link block #%u", __func__, counted_links); |
|
611 + return MSG_NG; |
|
612 + } |
|
613 + link = (struct router_lsa_link *)((caddr_t) link + thislinklen); |
|
614 + linkbytes -= thislinklen; |
|
615 + counted_links++; |
|
616 + } |
|
617 + if (counted_links != num_links) |
|
618 + { |
|
619 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
620 + zlog_debug ("%s: %u link blocks declared, %u present", |
|
621 + __func__, num_links, counted_links); |
|
622 + return MSG_NG; |
|
623 + } |
|
624 + return MSG_OK; |
|
625 +} |
|
626 + |
|
627 +/* Verify, that the given LSA is properly sized/aligned (including type-specific |
|
628 + minimum length constraint). */ |
|
629 +static unsigned |
|
630 +ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char headeronly) |
|
631 +{ |
|
632 + unsigned ret; |
|
633 + struct router_lsa * rlsa; |
|
634 + if |
|
635 + ( |
|
636 + lsah->type < OSPF_MAX_LSA && |
|
637 + ospf_lsa_minlen[lsah->type] && |
|
638 + lsalen < OSPF_LSA_HEADER_SIZE + ospf_lsa_minlen[lsah->type] |
|
639 + ) |
|
640 + { |
|
641 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
642 + zlog_debug ("%s: undersized (%u B) %s", |
|
643 + __func__, lsalen, LOOKUP (ospf_lsa_type_msg, lsah->type)); |
|
644 + return MSG_NG; |
|
645 + } |
|
646 + switch (lsah->type) |
|
647 + { |
|
648 + case OSPF_ROUTER_LSA: |
|
649 + /* RFC2328 A.4.2, LSA header + 4 bytes followed by N>=1 (12+)-byte link blocks */ |
|
650 + if (headeronly) |
|
651 + { |
|
652 + ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; |
|
653 + break; |
|
654 + } |
|
655 + rlsa = (struct router_lsa *) lsah; |
|
656 + ret = ospf_router_lsa_links_examin |
|
657 + ( |
|
658 + (struct router_lsa_link *) rlsa->link, |
|
659 + lsalen - OSPF_LSA_HEADER_SIZE - 4, /* skip: basic header, "flags", 0, "# links" */ |
|
660 + ntohs (rlsa->links) /* 16 bits */ |
|
661 + ); |
|
662 + break; |
|
663 + case OSPF_AS_EXTERNAL_LSA: |
|
664 + /* RFC2328 A.4.5, LSA header + 4 bytes followed by N>=1 12-bytes long blocks */ |
|
665 + case OSPF_AS_NSSA_LSA: |
|
666 + /* RFC3101 C, idem */ |
|
667 + ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_AS_EXTERNAL_LSA_MIN_SIZE) % 12 ? MSG_NG : MSG_OK; |
|
668 + break; |
|
669 + /* Following LSA types are considered OK length-wise as soon as their minimum |
|
670 + * length constraint is met and length of the whole LSA is a multiple of 4 |
|
671 + * (basic LSA header size is already a multiple of 4). */ |
|
672 + case OSPF_NETWORK_LSA: |
|
673 + /* RFC2328 A.4.3, LSA header + 4 bytes followed by N>=1 router-IDs */ |
|
674 + case OSPF_SUMMARY_LSA: |
|
675 + case OSPF_ASBR_SUMMARY_LSA: |
|
676 + /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS blocks */ |
|
677 +#ifdef HAVE_OPAQUE_LSA |
|
678 + case OSPF_OPAQUE_LINK_LSA: |
|
679 + case OSPF_OPAQUE_AREA_LSA: |
|
680 + case OSPF_OPAQUE_AS_LSA: |
|
681 + /* RFC5250 A.2, "some number of octets (of application-specific |
|
682 + * data) padded to 32-bit alignment." This is considered equivalent |
|
683 + * to 4-byte alignment of all other LSA types, see OSPF-ALIGNMENT.txt |
|
684 + * file for the detailed analysis of this passage. */ |
|
685 +#endif |
|
686 + ret = lsalen % 4 ? MSG_NG : MSG_OK; |
|
687 + break; |
|
688 + default: |
|
689 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
690 + zlog_debug ("%s: unsupported LSA type 0x%02x", __func__, lsah->type); |
|
691 + return MSG_NG; |
|
692 + } |
|
693 + if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
694 + zlog_debug ("%s: alignment error in %s", |
|
695 + __func__, LOOKUP (ospf_lsa_type_msg, lsah->type)); |
|
696 + return ret; |
|
697 +} |
|
698 + |
|
699 +/* Verify if the provided input buffer is a valid sequence of LSAs. This |
|
700 + includes verification of LSA blocks length/alignment and dispatching |
|
701 + of deeper-level checks. */ |
|
702 +static unsigned |
|
703 +ospf_lsaseq_examin |
|
704 +( |
|
705 + struct lsa_header *lsah, /* start of buffered data */ |
|
706 + size_t length, |
|
707 + const u_char headeronly, |
|
708 + /* When declared_num_lsas is not 0, compare it to the real number of LSAs |
|
709 + and treat the difference as an error. */ |
|
710 + const u_int32_t declared_num_lsas |
|
711 +) |
|
712 +{ |
|
713 + u_int32_t counted_lsas = 0; |
|
714 + |
|
715 + while (length) |
|
716 + { |
|
717 + u_int16_t lsalen; |
|
718 + if (length < OSPF_LSA_HEADER_SIZE) |
|
719 + { |
|
720 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
721 + zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header", |
|
722 + __func__, length, counted_lsas); |
|
723 + return MSG_NG; |
|
724 + } |
|
725 + /* save on ntohs() calls here and in the LSA validator */ |
|
726 + lsalen = ntohs (lsah->length); |
|
727 + if (lsalen < OSPF_LSA_HEADER_SIZE) |
|
728 + { |
|
729 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
730 + zlog_debug ("%s: malformed LSA header #%u, declared length is %u B", |
|
731 + __func__, counted_lsas, lsalen); |
|
732 + return MSG_NG; |
|
733 + } |
|
734 + if (headeronly) |
|
735 + { |
|
736 + /* less checks here and in ospf_lsa_examin() */ |
|
737 + if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 1)) |
|
738 + { |
|
739 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
740 + zlog_debug ("%s: malformed header-only LSA #%u", __func__, counted_lsas); |
|
741 + return MSG_NG; |
|
742 + } |
|
743 + lsah = (struct lsa_header *) ((caddr_t) lsah + OSPF_LSA_HEADER_SIZE); |
|
744 + length -= OSPF_LSA_HEADER_SIZE; |
|
745 + } |
|
746 + else |
|
747 + { |
|
748 + /* make sure the input buffer is deep enough before further checks */ |
|
749 + if (lsalen > length) |
|
750 + { |
|
751 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
752 + zlog_debug ("%s: anomaly in LSA #%u: declared length is %u B, buffered length is %zu B", |
|
753 + __func__, counted_lsas, lsalen, length); |
|
754 + return MSG_NG; |
|
755 + } |
|
756 + if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 0)) |
|
757 + { |
|
758 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
759 + zlog_debug ("%s: malformed LSA #%u", __func__, counted_lsas); |
|
760 + return MSG_NG; |
|
761 + } |
|
762 + lsah = (struct lsa_header *) ((caddr_t) lsah + lsalen); |
|
763 + length -= lsalen; |
|
764 + } |
|
765 + counted_lsas++; |
|
766 + } |
|
767 + |
|
768 + if (declared_num_lsas && counted_lsas != declared_num_lsas) |
|
769 + { |
|
770 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
771 + zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)", |
|
772 + __func__, declared_num_lsas, counted_lsas); |
|
773 + return MSG_NG; |
|
774 + } |
|
775 + return MSG_OK; |
|
776 +} |
|
777 + |
|
778 /* Verify a complete OSPF packet for proper sizing/alignment. */ |
|
779 static unsigned |
|
780 ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
781 { |
|
782 u_int16_t bytesdeclared; |
|
783 + unsigned ret; |
|
784 + struct ospf_ls_update * lsupd; |
|
785 |
|
786 /* Length, 1st approximation. */ |
|
787 if (bytesonwire < OSPF_HEADER_SIZE) |
|
788 @@ -2348,7 +2554,59 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
789 bytesdeclared, LOOKUP (ospf_packet_type_str, oh->type)); |
|
790 return MSG_NG; |
|
791 } |
|
792 - return MSG_OK; |
|
793 + switch (oh->type) |
|
794 + { |
|
795 + case OSPF_MSG_HELLO: |
|
796 + /* RFC2328 A.3.2, packet header + OSPF_HELLO_MIN_SIZE bytes followed |
|
797 + by N>=0 router-IDs. */ |
|
798 + ret = (bytesonwire - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; |
|
799 + break; |
|
800 + case OSPF_MSG_DB_DESC: |
|
801 + /* RFC2328 A.3.3, packet header + OSPF_DB_DESC_MIN_SIZE bytes followed |
|
802 + by N>=0 header-only LSAs. */ |
|
803 + ret = ospf_lsaseq_examin |
|
804 + ( |
|
805 + (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE), |
|
806 + bytesonwire - OSPF_HEADER_SIZE - OSPF_DB_DESC_MIN_SIZE, |
|
807 + 1, /* header-only LSAs */ |
|
808 + 0 |
|
809 + ); |
|
810 + break; |
|
811 + case OSPF_MSG_LS_REQ: |
|
812 + /* RFC2328 A.3.4, packet header followed by N>=0 12-bytes request blocks. */ |
|
813 + ret = (bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE) % |
|
814 + OSPF_LSA_KEY_SIZE ? MSG_NG : MSG_OK; |
|
815 + break; |
|
816 + case OSPF_MSG_LS_UPD: |
|
817 + /* RFC2328 A.3.5, packet header + OSPF_LS_UPD_MIN_SIZE bytes followed |
|
818 + by N>=0 full LSAs (with N declared beforehand). */ |
|
819 + lsupd = (struct ospf_ls_update *) ((caddr_t) oh + OSPF_HEADER_SIZE); |
|
820 + ret = ospf_lsaseq_examin |
|
821 + ( |
|
822 + (struct lsa_header *) ((caddr_t) lsupd + OSPF_LS_UPD_MIN_SIZE), |
|
823 + bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE, |
|
824 + 0, /* full LSAs */ |
|
825 + ntohl (lsupd->num_lsas) /* 32 bits */ |
|
826 + ); |
|
827 + break; |
|
828 + case OSPF_MSG_LS_ACK: |
|
829 + /* RFC2328 A.3.6, packet header followed by N>=0 header-only LSAs. */ |
|
830 + ret = ospf_lsaseq_examin |
|
831 + ( |
|
832 + (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_LS_ACK_MIN_SIZE), |
|
833 + bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE, |
|
834 + 1, /* header-only LSAs */ |
|
835 + 0 |
|
836 + ); |
|
837 + break; |
|
838 + default: |
|
839 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
840 + zlog_debug ("%s: invalid packet type 0x%02x", __func__, oh->type); |
|
841 + return MSG_NG; |
|
842 + } |
|
843 + if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
844 + zlog_debug ("%s: malformed %s packet", __func__, LOOKUP (ospf_packet_type_str, oh->type)); |
|
845 + return ret; |
|
846 } |
|
847 |
|
848 /* OSPF Header verification. */ |
|
849 diff --git ospfd/ospf_packet.h ospfd/ospf_packet.h |
|
850 index 3cbe889..337686a 100644 |
|
851 --- ospfd/ospf_packet.h |
|
852 +++ ospfd/ospf_packet.h |
|
853 @@ -121,6 +121,10 @@ struct ospf_db_desc |
|
854 u_int32_t dd_seqnum; |
|
855 }; |
|
856 |
|
857 +struct ospf_ls_update |
|
858 +{ |
|
859 + u_int32_t num_lsas; |
|
860 +}; |
|
861 |
|
862 /* Macros. */ |
|
863 /* XXX Perhaps obsolete; function in ospf_packet.c */ |
|
864 -- |
|
865 cgit v0.9.0.2 |
|
866 From b03ae9f2d22acd8e3f97714a9c0df744676e344d Mon Sep 17 00:00:00 2001 |
|
867 From: Denis Ovsienko <[email protected]> |
|
868 Date: Mon, 20 Feb 2012 19:08:10 +0000 |
|
869 Subject: ospfd: fix packet length check for auth/LLS cases |
|
870 |
|
871 An OSPFv2 packet with trailing data blocks (authentication and/or |
|
872 link-local signaling) failed the recently implemented packet length |
|
873 check, because trailing data length isn't counted in the packet header |
|
874 "length" field. This commit fixes respective check conditions. |
|
875 |
|
876 * ospf_packet.c |
|
877 * ospf_packet_examin(): use "bytesdeclared" instead of "bytesonwire" |
|
878 --- |
|
879 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
880 index 3b82820..7b661a3 100644 |
|
881 --- ospfd/ospf_packet.c |
|
882 +++ ospfd/ospf_packet.c |
|
883 @@ -2559,7 +2559,7 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
884 case OSPF_MSG_HELLO: |
|
885 /* RFC2328 A.3.2, packet header + OSPF_HELLO_MIN_SIZE bytes followed |
|
886 by N>=0 router-IDs. */ |
|
887 - ret = (bytesonwire - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; |
|
888 + ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; |
|
889 break; |
|
890 case OSPF_MSG_DB_DESC: |
|
891 /* RFC2328 A.3.3, packet header + OSPF_DB_DESC_MIN_SIZE bytes followed |
|
892 @@ -2567,14 +2567,14 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
893 ret = ospf_lsaseq_examin |
|
894 ( |
|
895 (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE), |
|
896 - bytesonwire - OSPF_HEADER_SIZE - OSPF_DB_DESC_MIN_SIZE, |
|
897 + bytesdeclared - OSPF_HEADER_SIZE - OSPF_DB_DESC_MIN_SIZE, |
|
898 1, /* header-only LSAs */ |
|
899 0 |
|
900 ); |
|
901 break; |
|
902 case OSPF_MSG_LS_REQ: |
|
903 /* RFC2328 A.3.4, packet header followed by N>=0 12-bytes request blocks. */ |
|
904 - ret = (bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE) % |
|
905 + ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE) % |
|
906 OSPF_LSA_KEY_SIZE ? MSG_NG : MSG_OK; |
|
907 break; |
|
908 case OSPF_MSG_LS_UPD: |
|
909 @@ -2584,7 +2584,7 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
910 ret = ospf_lsaseq_examin |
|
911 ( |
|
912 (struct lsa_header *) ((caddr_t) lsupd + OSPF_LS_UPD_MIN_SIZE), |
|
913 - bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE, |
|
914 + bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE, |
|
915 0, /* full LSAs */ |
|
916 ntohl (lsupd->num_lsas) /* 32 bits */ |
|
917 ); |
|
918 @@ -2594,7 +2594,7 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
919 ret = ospf_lsaseq_examin |
|
920 ( |
|
921 (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_LS_ACK_MIN_SIZE), |
|
922 - bytesonwire - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE, |
|
923 + bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE, |
|
924 1, /* header-only LSAs */ |
|
925 0 |
|
926 ); |
|
927 -- |
|
928 cgit v0.9.0.2 |
|
929 From 1bdd96caefaa76883bece4d358a60dc890f1e375 Mon Sep 17 00:00:00 2001 |
|
930 From: Denis Ovsienko <[email protected]> |
|
931 Date: Sun, 26 Feb 2012 13:00:57 +0000 |
|
932 Subject: ospfd: introduce ospf_auth_type_str[] |
|
933 |
|
934 --- |
|
935 diff --git ospfd/ospf_dump.c ospfd/ospf_dump.c |
|
936 index 8ace095..7e11e25 100644 |
|
937 --- ospfd/ospf_dump.c |
|
938 +++ ospfd/ospf_dump.c |
|
939 @@ -115,6 +115,16 @@ const struct message ospf_network_type_msg[] = |
|
940 }; |
|
941 const int ospf_network_type_msg_max = OSPF_IFTYPE_MAX; |
|
942 |
|
943 +/* AuType */ |
|
944 +const struct message ospf_auth_type_str[] = |
|
945 +{ |
|
946 + { OSPF_AUTH_NULL, "Null" }, |
|
947 + { OSPF_AUTH_SIMPLE, "Simple" }, |
|
948 + { OSPF_AUTH_CRYPTOGRAPHIC, "Cryptographic" }, |
|
949 +}; |
|
950 +const size_t ospf_auth_type_str_max = sizeof (ospf_auth_type_str) / |
|
951 + sizeof (ospf_auth_type_str[0]); |
|
952 + |
|
953 /* Configuration debug option variables. */ |
|
954 unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; |
|
955 unsigned long conf_debug_ospf_event = 0; |
|
956 @@ -657,6 +667,7 @@ static void |
|
957 ospf_header_dump (struct ospf_header *ospfh) |
|
958 { |
|
959 char buf[9]; |
|
960 + u_int16_t auth_type = ntohs (ospfh->auth_type); |
|
961 |
|
962 zlog_debug ("Header"); |
|
963 zlog_debug (" Version %d", ospfh->version); |
|
964 @@ -666,9 +677,9 @@ ospf_header_dump (struct ospf_header *ospfh) |
|
965 zlog_debug (" Router ID %s", inet_ntoa (ospfh->router_id)); |
|
966 zlog_debug (" Area ID %s", inet_ntoa (ospfh->area_id)); |
|
967 zlog_debug (" Checksum 0x%x", ntohs (ospfh->checksum)); |
|
968 - zlog_debug (" AuType %d", ntohs (ospfh->auth_type)); |
|
969 + zlog_debug (" AuType %s", LOOKUP (ospf_auth_type_str, auth_type)); |
|
970 |
|
971 - switch (ntohs (ospfh->auth_type)) |
|
972 + switch (auth_type) |
|
973 { |
|
974 case OSPF_AUTH_NULL: |
|
975 break; |
|
976 diff --git ospfd/ospf_dump.h ospfd/ospf_dump.h |
|
977 index 455214f..a2d5e8b 100644 |
|
978 --- ospfd/ospf_dump.h |
|
979 +++ ospfd/ospf_dump.h |
|
980 @@ -122,6 +122,8 @@ extern unsigned long term_debug_ospf_nssa; |
|
981 |
|
982 /* Message Strings. */ |
|
983 extern char *ospf_lsa_type_str[]; |
|
984 +extern const struct message ospf_auth_type_str[]; |
|
985 +extern const size_t ospf_auth_type_str_max; |
|
986 |
|
987 /* Prototypes. */ |
|
988 extern const char *ospf_area_name_string (struct ospf_area *); |
|
989 -- |
|
990 cgit v0.9.0.2 |
|
991 From e5fa148725fb2a3d1a8df12683f023ff9d65273f Mon Sep 17 00:00:00 2001 |
|
992 From: Denis Ovsienko <[email protected]> |
|
993 Date: Sun, 26 Feb 2012 13:59:43 +0000 |
|
994 Subject: ospfd: bring ospf_check_auth() into focus |
|
995 |
|
996 The old ospf_check_auth() function did two different jobs depending on |
|
997 AuType. For Null and Simple cases it actually authenticated the packet, |
|
998 but for Cryptographic case it only checked declared packet size (not |
|
999 taking the actual number of bytes on wire into account). The calling |
|
1000 function, ospf_verify_header(), had its own set of MD5/checksum checks |
|
1001 dispatched depending on AuType. |
|
1002 |
|
1003 This commit makes the packet size check work against the real number of |
|
1004 bytes and moves it to ospf_packet_examine(). All MD5/checksum |
|
1005 verification is now performed in ospf_check_auth() function. |
|
1006 |
|
1007 * ospf_packet.c |
|
1008 * ospf_packet_examin(): check length with MD5 bytes in mind |
|
1009 * ospf_verify_header(): remove all AuType-specific code |
|
1010 * ospf_check_auth(): completely rewrite |
|
1011 --- |
|
1012 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
1013 index 7b661a3..05651d3 100644 |
|
1014 --- ospfd/ospf_packet.c |
|
1015 +++ ospfd/ospf_packet.c |
|
1016 @@ -91,6 +91,9 @@ static const u_int16_t ospf_lsa_minlen[] = |
|
1017 0, |
|
1018 }; |
|
1019 |
|
1020 +/* for ospf_check_auth() */ |
|
1021 +static int ospf_check_sum (struct ospf_header *); |
|
1022 + |
|
1023 /* OSPF authentication checking function */ |
|
1024 static int |
|
1025 ospf_auth_type (struct ospf_interface *oi) |
|
1026 @@ -2262,44 +2265,91 @@ ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src) |
|
1027 return 0; |
|
1028 } |
|
1029 |
|
1030 +/* Return 1, if the packet is properly authenticated and checksummed, |
|
1031 + 0 otherwise. In particular, check that AuType header field is valid and |
|
1032 + matches the locally configured AuType, and that D.5 requirements are met. */ |
|
1033 static int |
|
1034 ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh) |
|
1035 { |
|
1036 - int ret = 0; |
|
1037 struct crypt_key *ck; |
|
1038 + u_int16_t iface_auth_type; |
|
1039 + u_int16_t pkt_auth_type = ntohs (ospfh->auth_type); |
|
1040 |
|
1041 - switch (ntohs (ospfh->auth_type)) |
|
1042 + switch (pkt_auth_type) |
|
1043 + { |
|
1044 + case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */ |
|
1045 + if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type (oi))) |
|
1046 { |
|
1047 - case OSPF_AUTH_NULL: |
|
1048 - ret = 1; |
|
1049 - break; |
|
1050 - case OSPF_AUTH_SIMPLE: |
|
1051 - if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) |
|
1052 - ret = 1; |
|
1053 - else |
|
1054 - ret = 0; |
|
1055 - break; |
|
1056 - case OSPF_AUTH_CRYPTOGRAPHIC: |
|
1057 - if ((ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) == NULL) |
|
1058 - { |
|
1059 - ret = 0; |
|
1060 - break; |
|
1061 - } |
|
1062 - |
|
1063 - /* This is very basic, the digest processing is elsewhere */ |
|
1064 - if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE && |
|
1065 - ospfh->u.crypt.key_id == ck->key_id && |
|
1066 - ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE <= OSPF_MAX_PACKET_SIZE) |
|
1067 - ret = 1; |
|
1068 - else |
|
1069 - ret = 0; |
|
1070 - break; |
|
1071 - default: |
|
1072 - ret = 0; |
|
1073 - break; |
|
1074 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1075 + zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null", |
|
1076 + IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); |
|
1077 + return 0; |
|
1078 } |
|
1079 - |
|
1080 - return ret; |
|
1081 + if (! ospf_check_sum (ospfh)) |
|
1082 + { |
|
1083 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1084 + zlog_warn ("interface %s: Null auth OK, but checksum error, Router-ID %s", |
|
1085 + IF_NAME (oi), inet_ntoa (ospfh->router_id)); |
|
1086 + return 0; |
|
1087 + } |
|
1088 + return 1; |
|
1089 + case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */ |
|
1090 + if (OSPF_AUTH_SIMPLE != (iface_auth_type = ospf_auth_type (oi))) |
|
1091 + { |
|
1092 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1093 + zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Simple", |
|
1094 + IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); |
|
1095 + return 0; |
|
1096 + } |
|
1097 + if (memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) |
|
1098 + { |
|
1099 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1100 + zlog_warn ("interface %s: Simple auth failed", IF_NAME (oi)); |
|
1101 + return 0; |
|
1102 + } |
|
1103 + if (! ospf_check_sum (ospfh)) |
|
1104 + { |
|
1105 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1106 + zlog_warn ("interface %s: Simple auth OK, checksum error, Router-ID %s", |
|
1107 + IF_NAME (oi), inet_ntoa (ospfh->router_id)); |
|
1108 + return 0; |
|
1109 + } |
|
1110 + return 1; |
|
1111 + case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */ |
|
1112 + if (OSPF_AUTH_CRYPTOGRAPHIC != (iface_auth_type = ospf_auth_type (oi))) |
|
1113 + { |
|
1114 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1115 + zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Cryptographic", |
|
1116 + IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); |
|
1117 + return 0; |
|
1118 + } |
|
1119 + if (ospfh->checksum) |
|
1120 + { |
|
1121 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1122 + zlog_warn ("interface %s: OSPF header checksum is not 0", IF_NAME (oi)); |
|
1123 + return 0; |
|
1124 + } |
|
1125 + /* only MD5 crypto method can pass ospf_packet_examin() */ |
|
1126 + if |
|
1127 + ( |
|
1128 + NULL == (ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) || |
|
1129 + ospfh->u.crypt.key_id != ck->key_id || |
|
1130 + /* Condition above uses the last key ID on the list, which is |
|
1131 + different from what ospf_crypt_key_lookup() does. A bug? */ |
|
1132 + ! ospf_check_md5_digest (oi, ospfh) |
|
1133 + ) |
|
1134 + { |
|
1135 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1136 + zlog_warn ("interface %s: MD5 auth failed", IF_NAME (oi)); |
|
1137 + return 0; |
|
1138 + } |
|
1139 + return 1; |
|
1140 + default: |
|
1141 + if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) |
|
1142 + zlog_warn ("interface %s: invalid packet auth-type (%02x)", |
|
1143 + IF_NAME (oi), pkt_auth_type); |
|
1144 + return 0; |
|
1145 + } |
|
1146 } |
|
1147 |
|
1148 static int |
|
1149 @@ -2518,7 +2568,7 @@ ospf_lsaseq_examin |
|
1150 static unsigned |
|
1151 ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
1152 { |
|
1153 - u_int16_t bytesdeclared; |
|
1154 + u_int16_t bytesdeclared, bytesauth; |
|
1155 unsigned ret; |
|
1156 struct ospf_ls_update * lsupd; |
|
1157 |
|
1158 @@ -2533,11 +2583,24 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
1159 * for possible extra bytes of crypto auth/padding, which are not counted |
|
1160 * in the OSPF header "length" field. */ |
|
1161 bytesdeclared = ntohs (oh->length); |
|
1162 - if (bytesdeclared > bytesonwire) |
|
1163 + if (ntohs (oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) |
|
1164 + bytesauth = 0; |
|
1165 + else |
|
1166 + { |
|
1167 + if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE) |
|
1168 + { |
|
1169 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
1170 + zlog_debug ("%s: unsupported crypto auth length (%u B)", |
|
1171 + __func__, oh->u.crypt.auth_data_len); |
|
1172 + return MSG_NG; |
|
1173 + } |
|
1174 + bytesauth = OSPF_AUTH_MD5_SIZE; |
|
1175 + } |
|
1176 + if (bytesdeclared + bytesauth > bytesonwire) |
|
1177 { |
|
1178 if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
1179 - zlog_debug ("%s: packet length error (%u real, %u declared)", |
|
1180 - __func__, bytesonwire, bytesdeclared); |
|
1181 + zlog_debug ("%s: packet length error (%u real, %u+%u declared)", |
|
1182 + __func__, bytesonwire, bytesdeclared, bytesauth); |
|
1183 return MSG_NG; |
|
1184 } |
|
1185 /* Length, 2nd approximation. The type-specific constraint is checked |
|
1186 @@ -2645,42 +2708,9 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, |
|
1187 return -1; |
|
1188 } |
|
1189 |
|
1190 - /* Check authentication. */ |
|
1191 - if (ospf_auth_type (oi) != ntohs (ospfh->auth_type)) |
|
1192 - { |
|
1193 - zlog_warn ("interface %s: auth-type mismatch, local %d, rcvd %d", |
|
1194 - IF_NAME (oi), ospf_auth_type (oi), ntohs (ospfh->auth_type)); |
|
1195 - return -1; |
|
1196 - } |
|
1197 - |
|
1198 + /* Check authentication. The function handles logging actions, where required. */ |
|
1199 if (! ospf_check_auth (oi, ospfh)) |
|
1200 - { |
|
1201 - zlog_warn ("interface %s: ospf_read authentication failed.", |
|
1202 - IF_NAME (oi)); |
|
1203 - return -1; |
|
1204 - } |
|
1205 - |
|
1206 - /* if check sum is invalid, packet is discarded. */ |
|
1207 - if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) |
|
1208 - { |
|
1209 - if (! ospf_check_sum (ospfh)) |
|
1210 - { |
|
1211 - zlog_warn ("interface %s: ospf_read packet checksum error %s", |
|
1212 - IF_NAME (oi), inet_ntoa (ospfh->router_id)); |
|
1213 - return -1; |
|
1214 - } |
|
1215 - } |
|
1216 - else |
|
1217 - { |
|
1218 - if (ospfh->checksum != 0) |
|
1219 - return -1; |
|
1220 - if (ospf_check_md5_digest (oi, ospfh) == 0) |
|
1221 - { |
|
1222 - zlog_warn ("interface %s: ospf_read md5 authentication failed.", |
|
1223 - IF_NAME (oi)); |
|
1224 - return -1; |
|
1225 - } |
|
1226 - } |
|
1227 + return -1; |
|
1228 |
|
1229 return 0; |
|
1230 } |
|
1231 -- |
|
1232 cgit v0.9.0.2 |
|
1233 From a59c5401a2df169de2c780f13a4563548c04a2b7 Mon Sep 17 00:00:00 2001 |
|
1234 From: Denis Ovsienko <[email protected]> |
|
1235 Date: Tue, 28 Feb 2012 11:15:29 +0000 |
|
1236 Subject: ospfd: reduce ospf_verify_header() |
|
1237 |
|
1238 Protocol version checks fits ospf_packet_examin() better (like it is |
|
1239 implemented in ospf6d), and packet type check is already there. |
|
1240 --- |
|
1241 diff --git ospfd/ospf_packet.c ospfd/ospf_packet.c |
|
1242 index 05651d3..de14ccc 100644 |
|
1243 --- ospfd/ospf_packet.c |
|
1244 +++ ospfd/ospf_packet.c |
|
1245 @@ -2582,6 +2582,12 @@ ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) |
|
1246 /* Now it is safe to access header fields. Performing length check, allow |
|
1247 * for possible extra bytes of crypto auth/padding, which are not counted |
|
1248 * in the OSPF header "length" field. */ |
|
1249 + if (oh->version != OSPF_VERSION) |
|
1250 + { |
|
1251 + if (IS_DEBUG_OSPF_PACKET (0, RECV)) |
|
1252 + zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version); |
|
1253 + return MSG_NG; |
|
1254 + } |
|
1255 bytesdeclared = ntohs (oh->length); |
|
1256 if (ntohs (oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) |
|
1257 bytesauth = 0; |
|
1258 @@ -2677,21 +2683,6 @@ static int |
|
1259 ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, |
|
1260 struct ip *iph, struct ospf_header *ospfh) |
|
1261 { |
|
1262 - /* check version. */ |
|
1263 - if (ospfh->version != OSPF_VERSION) |
|
1264 - { |
|
1265 - zlog_warn ("interface %s: ospf_read version number mismatch.", |
|
1266 - IF_NAME (oi)); |
|
1267 - return -1; |
|
1268 - } |
|
1269 - |
|
1270 - /* Valid OSPFv2 packet types are 1 through 5 inclusive. */ |
|
1271 - if (ospfh->type < 1 || ospfh->type > 5) |
|
1272 - { |
|
1273 - zlog_warn ("interface %s: invalid packet type %u", IF_NAME (oi), ospfh->type); |
|
1274 - return -1; |
|
1275 - } |
|
1276 - |
|
1277 /* Check Area ID. */ |
|
1278 if (!ospf_check_area_id (oi, ospfh)) |
|
1279 { |
|
1280 -- |
|
1281 cgit v0.9.0.2 |