]>
Commit | Line | Data |
---|---|---|
7f57883e DS |
1 | /* |
2 | * EIGRP General Sending and Receiving of EIGRP Packets. | |
3 | * Copyright (C) 2013-2014 | |
4 | * Authors: | |
5 | * Donnie Savage | |
6 | * Jan Janovic | |
7 | * Matej Perina | |
8 | * Peter Orsag | |
9 | * Peter Paluch | |
10 | * | |
11 | * This file is part of GNU Zebra. | |
12 | * | |
13 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
14 | * under the terms of the GNU General Public License as published by the | |
15 | * Free Software Foundation; either version 2, or (at your option) any | |
16 | * later version. | |
17 | * | |
18 | * GNU Zebra is distributed in the hope that it will be useful, but | |
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
21 | * General Public License for more details. | |
22 | * | |
896014f4 DL |
23 | * You should have received a copy of the GNU General Public License along |
24 | * with this program; see the file COPYING; if not, write to the Free Software | |
25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
7f57883e DS |
26 | */ |
27 | ||
28 | #include <zebra.h> | |
29 | ||
30 | #include "thread.h" | |
31 | #include "memory.h" | |
32 | #include "linklist.h" | |
33 | #include "vty.h" | |
34 | #include "keychain.h" | |
35 | #include "prefix.h" | |
36 | #include "if.h" | |
37 | #include "table.h" | |
38 | #include "sockunion.h" | |
39 | #include "stream.h" | |
40 | #include "log.h" | |
41 | #include "sockopt.h" | |
42 | #include "checksum.h" | |
43 | #include "md5.h" | |
44 | #include "sha256.h" | |
45 | ||
46 | #include "eigrpd/eigrp_structs.h" | |
47 | #include "eigrpd/eigrpd.h" | |
48 | #include "eigrpd/eigrp_interface.h" | |
49 | #include "eigrpd/eigrp_neighbor.h" | |
50 | #include "eigrpd/eigrp_packet.h" | |
51 | #include "eigrpd/eigrp_zebra.h" | |
52 | #include "eigrpd/eigrp_vty.h" | |
53 | #include "eigrpd/eigrp_dump.h" | |
54 | #include "eigrpd/eigrp_network.h" | |
55 | #include "eigrpd/eigrp_topology.h" | |
56 | #include "eigrpd/eigrp_fsm.h" | |
57 | #include "eigrpd/eigrp_memory.h" | |
58 | ||
59 | /* Packet Type String. */ | |
d62a17ae | 60 | const struct message eigrp_packet_type_str[] = { |
61 | {EIGRP_OPC_UPDATE, "Update"}, | |
62 | {EIGRP_OPC_REQUEST, "Request"}, | |
63 | {EIGRP_OPC_QUERY, "Query"}, | |
64 | {EIGRP_OPC_REPLY, "Reply"}, | |
65 | {EIGRP_OPC_HELLO, "Hello"}, | |
66 | {EIGRP_OPC_IPXSAP, "IPX-SAP"}, | |
67 | {EIGRP_OPC_PROBE, "Probe"}, | |
68 | {EIGRP_OPC_ACK, "Ack"}, | |
69 | {EIGRP_OPC_SIAQUERY, "SIAQuery"}, | |
70 | {EIGRP_OPC_SIAREPLY, "SIAReply"}, | |
71 | {0}}; | |
f9e5c9ca | 72 | |
7f57883e DS |
73 | |
74 | static unsigned char zeropad[16] = {0}; | |
75 | ||
76 | /* Forward function reference*/ | |
d62a17ae | 77 | static struct stream *eigrp_recv_packet(int, struct interface **, |
78 | struct stream *); | |
79 | static int eigrp_verify_header(struct stream *, struct eigrp_interface *, | |
80 | struct ip *, struct eigrp_header *); | |
81 | static int eigrp_check_network_mask(struct eigrp_interface *, struct in_addr); | |
82 | ||
83 | static int eigrp_retrans_count_exceeded(struct eigrp_packet *ep, | |
84 | struct eigrp_neighbor *nbr) | |
7f57883e | 85 | { |
d62a17ae | 86 | return 1; |
7f57883e DS |
87 | } |
88 | ||
d62a17ae | 89 | int eigrp_make_md5_digest(struct eigrp_interface *ei, struct stream *s, |
90 | u_char flags) | |
7f57883e | 91 | { |
d62a17ae | 92 | struct key *key = NULL; |
93 | struct keychain *keychain; | |
94 | ||
95 | unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN]; | |
96 | MD5_CTX ctx; | |
97 | u_char *ibuf; | |
98 | size_t backup_get, backup_end; | |
99 | struct TLV_MD5_Authentication_Type *auth_TLV; | |
100 | ||
101 | ibuf = s->data; | |
102 | backup_end = s->endp; | |
103 | backup_get = s->getp; | |
104 | ||
105 | auth_TLV = eigrp_authTLV_MD5_new(); | |
106 | ||
107 | stream_set_getp(s, EIGRP_HEADER_LEN); | |
108 | stream_get(auth_TLV, s, EIGRP_AUTH_MD5_TLV_SIZE); | |
109 | stream_set_getp(s, backup_get); | |
110 | ||
111 | keychain = keychain_lookup(IF_DEF_PARAMS(ei->ifp)->auth_keychain); | |
112 | if (keychain) | |
113 | key = key_lookup_for_send(keychain); | |
114 | else { | |
115 | eigrp_authTLV_MD5_free(auth_TLV); | |
116 | return EIGRP_AUTH_TYPE_NONE; | |
117 | } | |
118 | ||
119 | memset(&ctx, 0, sizeof(ctx)); | |
120 | MD5Init(&ctx); | |
121 | ||
122 | /* Generate a digest. Each situation needs different handling */ | |
123 | if (flags & EIGRP_AUTH_BASIC_HELLO_FLAG) { | |
124 | MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); | |
125 | MD5Update(&ctx, key->string, strlen(key->string)); | |
126 | if (strlen(key->string) < 16) | |
127 | MD5Update(&ctx, zeropad, 16 - strlen(key->string)); | |
128 | } else if (flags & EIGRP_AUTH_UPDATE_INIT_FLAG) { | |
129 | MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE); | |
130 | } else if (flags & EIGRP_AUTH_UPDATE_FLAG) { | |
131 | MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); | |
132 | MD5Update(&ctx, key->string, strlen(key->string)); | |
133 | if (strlen(key->string) < 16) | |
134 | MD5Update(&ctx, zeropad, 16 - strlen(key->string)); | |
135 | if (backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)) { | |
136 | MD5Update(&ctx, | |
9d303b37 DL |
137 | ibuf + (EIGRP_HEADER_LEN |
138 | + EIGRP_AUTH_MD5_TLV_SIZE), | |
d62a17ae | 139 | backup_end - 20 |
140 | - (EIGRP_HEADER_LEN | |
141 | + EIGRP_AUTH_MD5_TLV_SIZE)); | |
142 | } | |
143 | } | |
144 | ||
145 | MD5Final(digest, &ctx); | |
146 | ||
147 | /* Append md5 digest to the end of the stream. */ | |
148 | memcpy(auth_TLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN); | |
149 | ||
150 | stream_set_endp(s, EIGRP_HEADER_LEN); | |
151 | stream_put(s, auth_TLV, EIGRP_AUTH_MD5_TLV_SIZE); | |
152 | stream_set_endp(s, backup_end); | |
153 | ||
154 | eigrp_authTLV_MD5_free(auth_TLV); | |
155 | return EIGRP_AUTH_TYPE_MD5_LEN; | |
7f57883e DS |
156 | } |
157 | ||
d62a17ae | 158 | int eigrp_check_md5_digest(struct stream *s, |
159 | struct TLV_MD5_Authentication_Type *authTLV, | |
160 | struct eigrp_neighbor *nbr, u_char flags) | |
7f57883e | 161 | { |
d62a17ae | 162 | MD5_CTX ctx; |
163 | unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN]; | |
164 | struct key *key = NULL; | |
165 | struct keychain *keychain; | |
166 | u_char *ibuf; | |
167 | size_t backup_end; | |
168 | struct TLV_MD5_Authentication_Type *auth_TLV; | |
169 | struct eigrp_header *eigrph; | |
170 | ||
171 | if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(authTLV->key_sequence)) { | |
172 | zlog_warn( | |
173 | "interface %s: eigrp_check_md5 bad sequence %d (expect %d)", | |
174 | IF_NAME(nbr->ei), ntohl(authTLV->key_sequence), | |
175 | ntohl(nbr->crypt_seqnum)); | |
176 | return 0; | |
177 | } | |
178 | ||
179 | eigrph = (struct eigrp_header *)s->data; | |
180 | eigrph->checksum = 0; | |
181 | ||
182 | auth_TLV = (struct TLV_MD5_Authentication_Type *)(s->data | |
183 | + EIGRP_HEADER_LEN); | |
184 | memset(auth_TLV->digest, 0, sizeof(auth_TLV->digest)); | |
185 | ||
186 | ibuf = s->data; | |
187 | backup_end = s->endp; | |
188 | ||
189 | keychain = keychain_lookup(IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain); | |
190 | if (keychain) | |
191 | key = key_lookup_for_send(keychain); | |
192 | ||
193 | memset(&ctx, 0, sizeof(ctx)); | |
194 | MD5Init(&ctx); | |
195 | ||
196 | /* Generate a digest. Each situation needs different handling */ | |
197 | if (flags & EIGRP_AUTH_BASIC_HELLO_FLAG) { | |
198 | MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); | |
199 | MD5Update(&ctx, key->string, strlen(key->string)); | |
200 | if (strlen(key->string) < 16) | |
201 | MD5Update(&ctx, zeropad, 16 - strlen(key->string)); | |
202 | } else if (flags & EIGRP_AUTH_UPDATE_INIT_FLAG) { | |
203 | MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE); | |
204 | } else if (flags & EIGRP_AUTH_UPDATE_FLAG) { | |
205 | MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE); | |
206 | MD5Update(&ctx, key->string, strlen(key->string)); | |
207 | if (strlen(key->string) < 16) | |
208 | MD5Update(&ctx, zeropad, 16 - strlen(key->string)); | |
209 | if (backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)) { | |
210 | MD5Update(&ctx, | |
9d303b37 DL |
211 | ibuf + (EIGRP_HEADER_LEN |
212 | + EIGRP_AUTH_MD5_TLV_SIZE), | |
d62a17ae | 213 | backup_end - 20 |
214 | - (EIGRP_HEADER_LEN | |
215 | + EIGRP_AUTH_MD5_TLV_SIZE)); | |
216 | } | |
217 | } | |
218 | ||
219 | MD5Final(digest, &ctx); | |
220 | ||
221 | /* compare the two */ | |
222 | if (memcmp(authTLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN) == 0) { | |
223 | zlog_debug("VSETKO OK"); | |
224 | } else { | |
225 | zlog_warn("interface %s: eigrp_check_md5 checksum mismatch", | |
226 | IF_NAME(nbr->ei)); | |
227 | return 0; | |
228 | } | |
229 | ||
230 | /* save neighbor's crypt_seqnum */ | |
231 | nbr->crypt_seqnum = authTLV->key_sequence; | |
232 | ||
233 | return 1; | |
7f57883e DS |
234 | } |
235 | ||
d62a17ae | 236 | int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s, |
237 | u_char flags) | |
7f57883e | 238 | { |
d62a17ae | 239 | struct key *key = NULL; |
240 | struct keychain *keychain; | |
241 | char *source_ip; | |
7f57883e | 242 | |
d62a17ae | 243 | unsigned char digest[EIGRP_AUTH_TYPE_SHA256_LEN]; |
244 | unsigned char buffer[1 + PLAINTEXT_LENGTH + 45 + 1] = {0}; | |
245 | HMAC_SHA256_CTX ctx; | |
246 | void *ibuf; | |
247 | size_t backup_get, backup_end; | |
248 | struct TLV_SHA256_Authentication_Type *auth_TLV; | |
7f57883e | 249 | |
d62a17ae | 250 | ibuf = s->data; |
251 | backup_end = s->endp; | |
252 | backup_get = s->getp; | |
7f57883e | 253 | |
d62a17ae | 254 | auth_TLV = eigrp_authTLV_SHA256_new(); |
7f57883e | 255 | |
d62a17ae | 256 | stream_set_getp(s, EIGRP_HEADER_LEN); |
257 | stream_get(auth_TLV, s, EIGRP_AUTH_SHA256_TLV_SIZE); | |
258 | stream_set_getp(s, backup_get); | |
7f57883e | 259 | |
d62a17ae | 260 | keychain = keychain_lookup(IF_DEF_PARAMS(ei->ifp)->auth_keychain); |
261 | if (keychain) | |
262 | key = key_lookup_for_send(keychain); | |
7f57883e | 263 | |
d62a17ae | 264 | // saved_len[index] = strnzcpyn(saved_key[index], key, |
265 | // PLAINTEXT_LENGTH + 1); | |
7f57883e | 266 | |
d62a17ae | 267 | source_ip = calloc(16, sizeof(char)); |
268 | inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, 16); | |
7f57883e | 269 | |
d62a17ae | 270 | memset(&ctx, 0, sizeof(ctx)); |
271 | buffer[0] = '\n'; | |
272 | memcpy(buffer + 1, key, strlen(key->string)); | |
273 | memcpy(buffer + 1 + strlen(key->string), source_ip, strlen(source_ip)); | |
274 | HMAC__SHA256_Init(&ctx, buffer, | |
275 | 1 + strlen(key->string) + strlen(source_ip)); | |
276 | HMAC__SHA256_Update(&ctx, ibuf, strlen(ibuf)); | |
277 | HMAC__SHA256_Final(digest, &ctx); | |
7f57883e DS |
278 | |
279 | ||
d62a17ae | 280 | /* Put hmac-sha256 digest to it's place */ |
281 | memcpy(auth_TLV->digest, digest, EIGRP_AUTH_TYPE_SHA256_LEN); | |
7f57883e | 282 | |
d62a17ae | 283 | stream_set_endp(s, EIGRP_HEADER_LEN); |
284 | stream_put(s, auth_TLV, EIGRP_AUTH_SHA256_TLV_SIZE); | |
285 | stream_set_endp(s, backup_end); | |
7f57883e | 286 | |
d62a17ae | 287 | eigrp_authTLV_SHA256_free(auth_TLV); |
288 | free(source_ip); | |
7f57883e | 289 | |
d62a17ae | 290 | return EIGRP_AUTH_TYPE_SHA256_LEN; |
7f57883e DS |
291 | } |
292 | ||
d62a17ae | 293 | int eigrp_check_sha256_digest(struct stream *s, |
294 | struct TLV_SHA256_Authentication_Type *authTLV, | |
295 | struct eigrp_neighbor *nbr, u_char flags) | |
7f57883e | 296 | { |
d62a17ae | 297 | return 1; |
7f57883e | 298 | } |
f9e5c9ca | 299 | |
7f57883e DS |
300 | /* |
301 | * eigrp_packet_dump | |
302 | * | |
303 | * This routing dumps the contents of the IP packet either received or | |
304 | * built by EIGRP. | |
305 | */ | |
d62a17ae | 306 | static void eigrp_packet_dump(struct stream *s) |
7f57883e | 307 | { |
d62a17ae | 308 | // not yet... |
309 | return; | |
7f57883e DS |
310 | } |
311 | ||
d62a17ae | 312 | int eigrp_write(struct thread *thread) |
7f57883e | 313 | { |
d62a17ae | 314 | struct eigrp *eigrp = THREAD_ARG(thread); |
315 | struct eigrp_header *eigrph; | |
316 | struct eigrp_interface *ei; | |
317 | struct eigrp_packet *ep; | |
318 | struct sockaddr_in sa_dst; | |
319 | struct ip iph; | |
320 | struct msghdr msg; | |
321 | struct iovec iov[2]; | |
322 | u_int16_t opcode = 0; | |
323 | ||
324 | int ret; | |
325 | int flags = 0; | |
326 | struct listnode *node; | |
7f57883e | 327 | #ifdef WANT_EIGRP_WRITE_FRAGMENT |
d62a17ae | 328 | static u_int16_t ipid = 0; |
9d303b37 DL |
329 | #endif /* WANT_EIGRP_WRITE_FRAGMENT */ |
330 | /* $FRR indent$ */ | |
331 | /* clang-format off */ | |
7f57883e DS |
332 | #define EIGRP_WRITE_IPHL_SHIFT 2 |
333 | ||
d62a17ae | 334 | eigrp->t_write = NULL; |
7f57883e | 335 | |
d62a17ae | 336 | node = listhead(eigrp->oi_write_q); |
337 | assert(node); | |
338 | ei = listgetdata(node); | |
339 | assert(ei); | |
7f57883e DS |
340 | |
341 | #ifdef WANT_EIGRP_WRITE_FRAGMENT | |
d62a17ae | 342 | /* seed ipid static with low order bits of time */ |
343 | if (ipid == 0) | |
344 | ipid = (time(NULL) & 0xffff); | |
7f57883e DS |
345 | #endif /* WANT_EIGRP_WRITE_FRAGMENT */ |
346 | ||
d62a17ae | 347 | /* Get one packet from queue. */ |
348 | ep = eigrp_fifo_head(ei->obuf); | |
349 | assert(ep); | |
350 | assert(ep->length >= EIGRP_HEADER_LEN); | |
7f57883e | 351 | |
d62a17ae | 352 | if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) |
353 | eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex); | |
7f57883e | 354 | |
d62a17ae | 355 | memset(&iph, 0, sizeof(struct ip)); |
356 | memset(&sa_dst, 0, sizeof(sa_dst)); | |
7f57883e | 357 | |
d62a17ae | 358 | sa_dst.sin_family = AF_INET; |
7f57883e | 359 | #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN |
d62a17ae | 360 | sa_dst.sin_len = sizeof(sa_dst); |
7f57883e | 361 | #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ |
d62a17ae | 362 | sa_dst.sin_addr = ep->dst; |
363 | sa_dst.sin_port = htons(0); | |
364 | ||
365 | /* Set DONTROUTE flag if dst is unicast. */ | |
366 | if (!IN_MULTICAST(htonl(ep->dst.s_addr))) | |
367 | flags = MSG_DONTROUTE; | |
368 | ||
369 | iph.ip_hl = sizeof(struct ip) >> EIGRP_WRITE_IPHL_SHIFT; | |
370 | /* it'd be very strange for header to not be 4byte-word aligned but.. */ | |
371 | if (sizeof(struct ip) | |
372 | > (unsigned int)(iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT)) | |
373 | iph.ip_hl++; /* we presume sizeof struct ip cant overflow | |
374 | ip_hl.. */ | |
375 | ||
376 | iph.ip_v = IPVERSION; | |
377 | iph.ip_tos = IPTOS_PREC_INTERNETCONTROL; | |
378 | iph.ip_len = (iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT) + ep->length; | |
379 | ||
380 | #if defined(__DragonFly__) | |
381 | /* | |
382 | * DragonFly's raw socket expects ip_len/ip_off in network byte order. | |
383 | */ | |
384 | iph.ip_len = htons(iph.ip_len); | |
7f57883e DS |
385 | #endif |
386 | ||
d62a17ae | 387 | iph.ip_off = 0; |
388 | iph.ip_ttl = EIGRP_IP_TTL; | |
389 | iph.ip_p = IPPROTO_EIGRPIGP; | |
390 | iph.ip_sum = 0; | |
391 | iph.ip_src.s_addr = ei->address->u.prefix4.s_addr; | |
392 | iph.ip_dst.s_addr = ep->dst.s_addr; | |
393 | ||
394 | memset(&msg, 0, sizeof(msg)); | |
395 | msg.msg_name = (caddr_t)&sa_dst; | |
396 | msg.msg_namelen = sizeof(sa_dst); | |
397 | msg.msg_iov = iov; | |
398 | msg.msg_iovlen = 2; | |
399 | ||
400 | iov[0].iov_base = (char *)&iph; | |
401 | iov[0].iov_len = iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT; | |
402 | iov[1].iov_base = STREAM_PNT(ep->s); | |
403 | iov[1].iov_len = ep->length; | |
404 | ||
405 | /* send final fragment (could be first) */ | |
406 | sockopt_iphdrincl_swab_htosys(&iph); | |
407 | ret = sendmsg(eigrp->fd, &msg, flags); | |
408 | sockopt_iphdrincl_swab_systoh(&iph); | |
409 | ||
410 | if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)) { | |
411 | eigrph = (struct eigrp_header *)STREAM_DATA(ep->s); | |
412 | opcode = eigrph->opcode; | |
413 | zlog_debug("Sending [%s] to [%s] via [%s] ret [%d].", | |
414 | lookup_msg(eigrp_packet_type_str, opcode, NULL), | |
415 | inet_ntoa(ep->dst), IF_NAME(ei), ret); | |
416 | } | |
417 | ||
418 | if (ret < 0) | |
419 | zlog_warn( | |
420 | "*** sendmsg in eigrp_write failed to %s, " | |
421 | "id %d, off %d, len %d, interface %s, mtu %u: %s", | |
422 | inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off, | |
423 | iph.ip_len, ei->ifp->name, ei->ifp->mtu, | |
424 | safe_strerror(errno)); | |
425 | ||
426 | /* Show debug sending packet. */ | |
427 | if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND) | |
428 | && (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))) { | |
429 | zlog_debug( | |
430 | "-----------------------------------------------------"); | |
431 | eigrp_ip_header_dump(&iph); | |
432 | stream_set_getp(ep->s, 0); | |
433 | eigrp_packet_dump(ep->s); | |
434 | zlog_debug( | |
435 | "-----------------------------------------------------"); | |
436 | } | |
437 | ||
438 | /* Now delete packet from queue. */ | |
439 | eigrp_packet_delete(ei); | |
440 | ||
441 | if (eigrp_fifo_head(ei->obuf) == NULL) { | |
442 | ei->on_write_q = 0; | |
443 | list_delete_node(eigrp->oi_write_q, node); | |
444 | } | |
445 | ||
446 | /* If packets still remain in queue, call write thread. */ | |
447 | if (!list_isempty(eigrp->oi_write_q)) { | |
448 | eigrp->t_write = NULL; | |
449 | thread_add_write(master, eigrp_write, eigrp, eigrp->fd, | |
450 | &eigrp->t_write); | |
451 | } | |
452 | ||
453 | return 0; | |
7f57883e DS |
454 | } |
455 | ||
456 | /* Starting point of packet process function. */ | |
d62a17ae | 457 | int eigrp_read(struct thread *thread) |
7f57883e | 458 | { |
d62a17ae | 459 | int ret; |
460 | struct stream *ibuf; | |
461 | struct eigrp *eigrp; | |
462 | struct eigrp_interface *ei; | |
463 | struct ip *iph; | |
464 | struct eigrp_header *eigrph; | |
465 | struct interface *ifp; | |
466 | struct eigrp_neighbor *nbr; | |
467 | ||
468 | u_int16_t opcode = 0; | |
469 | u_int16_t length = 0; | |
470 | ||
471 | /* first of all get interface pointer. */ | |
472 | eigrp = THREAD_ARG(thread); | |
473 | ||
474 | /* prepare for next packet. */ | |
475 | eigrp->t_read = NULL; | |
476 | thread_add_read(master, eigrp_read, eigrp, eigrp->fd, &eigrp->t_read); | |
477 | ||
478 | stream_reset(eigrp->ibuf); | |
479 | if (!(ibuf = eigrp_recv_packet(eigrp->fd, &ifp, eigrp->ibuf))) { | |
480 | /* This raw packet is known to be at least as big as its IP | |
481 | * header. */ | |
482 | return -1; | |
483 | } | |
484 | ||
485 | /* Note that there should not be alignment problems with this assignment | |
486 | because this is at the beginning of the stream data buffer. */ | |
487 | iph = (struct ip *)STREAM_DATA(ibuf); | |
488 | ||
489 | // Substract IPv4 header size from EIGRP Packet itself | |
490 | if (iph->ip_v == 4) | |
491 | length = (iph->ip_len) - 20U; | |
492 | ||
493 | ||
494 | /* IP Header dump. */ | |
495 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) | |
496 | && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL)) | |
497 | eigrp_ip_header_dump(iph); | |
498 | ||
499 | /* Note that sockopt_iphdrincl_swab_systoh was called in | |
500 | * eigrp_recv_packet. */ | |
501 | if (ifp == NULL) { | |
502 | struct connected *c; | |
503 | /* Handle cases where the platform does not support retrieving | |
504 | the ifindex, | |
505 | and also platforms (such as Solaris 8) that claim to support | |
506 | ifindex | |
507 | retrieval but do not. */ | |
508 | c = if_lookup_address((void *)&iph->ip_src, AF_INET, | |
509 | VRF_DEFAULT); | |
510 | ||
511 | if (c == NULL) | |
512 | return 0; | |
513 | ||
514 | ifp = c->ifp; | |
515 | } | |
516 | ||
517 | /* associate packet with eigrp interface */ | |
518 | ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp); | |
519 | ||
520 | /* eigrp_verify_header() relies on a valid "ei" and thus can be called | |
521 | only | |
522 | after the checks below are passed. These checks in turn access the | |
523 | fields of unverified "eigrph" structure for their own purposes and | |
524 | must remain very accurate in doing this. | |
525 | */ | |
526 | if (!ei) | |
527 | return 0; | |
528 | ||
529 | /* Self-originated packet should be discarded silently. */ | |
530 | if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) | |
531 | || (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4))) { | |
532 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) | |
533 | zlog_debug( | |
534 | "eigrp_read[%s]: Dropping self-originated packet", | |
535 | inet_ntoa(iph->ip_src)); | |
536 | return 0; | |
537 | } | |
538 | ||
539 | /* Advance from IP header to EIGRP header (iph->ip_hl has been verified | |
540 | by eigrp_recv_packet() to be correct). */ | |
541 | ||
542 | stream_forward_getp(ibuf, (iph->ip_hl * 4)); | |
543 | eigrph = (struct eigrp_header *)STREAM_PNT(ibuf); | |
544 | ||
545 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) | |
546 | && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL)) | |
547 | eigrp_header_dump(eigrph); | |
548 | ||
549 | // if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) - | |
550 | // stream_get_getp(ibuf))) | |
551 | // return -1; | |
552 | ||
553 | /* Now it is safe to access all fields of EIGRP packet header. */ | |
554 | /* associate packet with eigrp interface */ | |
555 | ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp); | |
556 | ||
557 | /* eigrp_verify_header() relies on a valid "ei" and thus can be called | |
558 | only | |
559 | after the checks below are passed. These checks in turn access the | |
560 | fields of unverified "eigrph" structure for their own purposes and | |
561 | must remain very accurate in doing this. | |
562 | */ | |
563 | if (!ei) | |
564 | return 0; | |
565 | ||
566 | /* If incoming interface is passive one, ignore it. */ | |
567 | if (ei && EIGRP_IF_PASSIVE_STATUS(ei) == EIGRP_IF_PASSIVE) { | |
568 | char buf[3][INET_ADDRSTRLEN]; | |
569 | ||
570 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) | |
571 | zlog_debug( | |
572 | "ignoring packet from router %s sent to %s, " | |
573 | "received on a passive interface, %s", | |
574 | inet_ntop(AF_INET, &eigrph->vrid, buf[0], | |
575 | sizeof(buf[0])), | |
576 | inet_ntop(AF_INET, &iph->ip_dst, buf[1], | |
577 | sizeof(buf[1])), | |
578 | inet_ntop(AF_INET, &ei->address->u.prefix4, | |
579 | buf[2], sizeof(buf[2]))); | |
580 | ||
581 | if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) { | |
582 | /* Try to fix multicast membership. | |
583 | * Some OS:es may have problems in this area, | |
584 | * make sure it is removed. | |
585 | */ | |
586 | EI_MEMBER_JOINED(ei, MEMBER_ALLROUTERS); | |
587 | eigrp_if_set_multicast(ei); | |
588 | } | |
589 | return 0; | |
590 | } | |
591 | ||
592 | /* else it must be a local eigrp interface, check it was received on | |
593 | * correct link | |
594 | */ | |
595 | else if (ei->ifp != ifp) { | |
596 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) | |
597 | zlog_warn("Packet from [%s] received on wrong link %s", | |
598 | inet_ntoa(iph->ip_src), ifp->name); | |
599 | return 0; | |
600 | } | |
601 | ||
602 | /* Verify more EIGRP header fields. */ | |
603 | ret = eigrp_verify_header(ibuf, ei, iph, eigrph); | |
604 | if (ret < 0) { | |
605 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) | |
606 | zlog_debug( | |
607 | "eigrp_read[%s]: Header check failed, dropping.", | |
608 | inet_ntoa(iph->ip_src)); | |
609 | return ret; | |
610 | } | |
611 | ||
612 | /* calcualte the eigrp packet length, and move the pounter to the | |
613 | start of the eigrp TLVs */ | |
614 | opcode = eigrph->opcode; | |
615 | ||
616 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) | |
617 | zlog_debug( | |
618 | "Received [%s] length [%u] via [%s] src [%s] dst [%s]", | |
619 | lookup_msg(eigrp_packet_type_str, opcode, NULL), length, | |
620 | IF_NAME(ei), inet_ntoa(iph->ip_src), | |
621 | inet_ntoa(iph->ip_dst)); | |
622 | ||
623 | /* Read rest of the packet and call each sort of packet routine. */ | |
624 | stream_forward_getp(ibuf, EIGRP_HEADER_LEN); | |
625 | ||
626 | /* New testing block of code for handling Acks */ | |
627 | if (ntohl(eigrph->ack) != 0) { | |
628 | nbr = eigrp_nbr_get(ei, eigrph, iph); | |
629 | ||
630 | /* neighbor must be valid, eigrp_nbr_get creates if none existed | |
631 | */ | |
632 | assert(nbr); | |
633 | ||
634 | struct eigrp_packet *ep; | |
635 | ||
636 | ep = eigrp_fifo_tail(nbr->retrans_queue); | |
637 | if (ep) { | |
638 | if (ntohl(eigrph->ack) == ep->sequence_number) { | |
639 | if ((nbr->state == EIGRP_NEIGHBOR_PENDING) | |
640 | && (ntohl(eigrph->ack) | |
641 | == nbr->init_sequence_number)) { | |
642 | eigrp_nbr_state_set(nbr, | |
643 | EIGRP_NEIGHBOR_UP); | |
644 | zlog_info( | |
645 | "Neighbor adjacency became full"); | |
646 | nbr->init_sequence_number = 0; | |
647 | nbr->recv_sequence_number = | |
648 | ntohl(eigrph->sequence); | |
649 | eigrp_update_send_EOT(nbr); | |
650 | } | |
651 | ep = eigrp_fifo_pop_tail(nbr->retrans_queue); | |
652 | eigrp_packet_free(ep); | |
653 | if (nbr->retrans_queue->count > 0) { | |
654 | eigrp_send_packet_reliably(nbr); | |
655 | } | |
656 | } | |
657 | } | |
658 | ep = eigrp_fifo_tail(nbr->multicast_queue); | |
659 | if (ep) { | |
660 | if (ntohl(eigrph->ack) == ep->sequence_number) { | |
661 | ep = eigrp_fifo_pop_tail(nbr->multicast_queue); | |
662 | eigrp_packet_free(ep); | |
663 | if (nbr->multicast_queue->count > 0) { | |
664 | eigrp_send_packet_reliably(nbr); | |
665 | } | |
666 | } | |
667 | } | |
668 | } | |
669 | ||
670 | ||
671 | switch (opcode) { | |
672 | case EIGRP_OPC_HELLO: | |
673 | eigrp_hello_receive(eigrp, iph, eigrph, ibuf, ei, length); | |
674 | break; | |
675 | case EIGRP_OPC_PROBE: | |
676 | // eigrp_probe_receive(eigrp, iph, eigrph, ibuf, ei, | |
677 | // length); | |
678 | break; | |
679 | case EIGRP_OPC_QUERY: | |
680 | eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length); | |
681 | break; | |
682 | case EIGRP_OPC_REPLY: | |
683 | eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length); | |
684 | break; | |
685 | case EIGRP_OPC_REQUEST: | |
686 | // eigrp_request_receive(eigrp, iph, eigrph, ibuf, ei, | |
687 | // length); | |
688 | break; | |
689 | case EIGRP_OPC_SIAQUERY: | |
690 | eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length); | |
691 | break; | |
692 | case EIGRP_OPC_SIAREPLY: | |
693 | eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length); | |
694 | break; | |
695 | case EIGRP_OPC_UPDATE: | |
696 | eigrp_update_receive(eigrp, iph, eigrph, ibuf, ei, length); | |
697 | break; | |
698 | default: | |
699 | zlog_warn( | |
700 | "interface %s: EIGRP packet header type %d unsupported", | |
701 | IF_NAME(ei), opcode); | |
702 | break; | |
703 | } | |
704 | ||
705 | return 0; | |
7f57883e DS |
706 | } |
707 | ||
d62a17ae | 708 | static struct stream *eigrp_recv_packet(int fd, struct interface **ifp, |
709 | struct stream *ibuf) | |
7f57883e | 710 | { |
d62a17ae | 711 | int ret; |
712 | struct ip *iph; | |
713 | u_int16_t ip_len; | |
714 | unsigned int ifindex = 0; | |
715 | struct iovec iov; | |
716 | /* Header and data both require alignment. */ | |
717 | char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; | |
718 | struct msghdr msgh; | |
719 | ||
720 | memset(&msgh, 0, sizeof(struct msghdr)); | |
721 | msgh.msg_iov = &iov; | |
722 | msgh.msg_iovlen = 1; | |
723 | msgh.msg_control = (caddr_t)buff; | |
724 | msgh.msg_controllen = sizeof(buff); | |
725 | ||
726 | ret = stream_recvmsg(ibuf, fd, &msgh, 0, (EIGRP_PACKET_MAX_LEN + 1)); | |
727 | if (ret < 0) { | |
728 | zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno)); | |
729 | return NULL; | |
730 | } | |
731 | if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */ | |
732 | { | |
733 | zlog_warn( | |
734 | "eigrp_recv_packet: discarding runt packet of length %d " | |
735 | "(ip header size is %u)", | |
736 | ret, (u_int)sizeof(iph)); | |
737 | return NULL; | |
738 | } | |
739 | ||
740 | /* Note that there should not be alignment problems with this assignment | |
741 | because this is at the beginning of the stream data buffer. */ | |
742 | iph = (struct ip *)STREAM_DATA(ibuf); | |
743 | sockopt_iphdrincl_swab_systoh(iph); | |
744 | ||
745 | ip_len = iph->ip_len; | |
746 | ||
747 | #if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000) | |
748 | /* | |
749 | * Kernel network code touches incoming IP header parameters, | |
750 | * before protocol specific processing. | |
751 | * | |
752 | * 1) Convert byteorder to host representation. | |
753 | * --> ip_len, ip_id, ip_off | |
754 | * | |
755 | * 2) Adjust ip_len to strip IP header size! | |
756 | * --> If user process receives entire IP packet via RAW | |
757 | * socket, it must consider adding IP header size to | |
758 | * the "ip_len" field of "ip" structure. | |
759 | * | |
760 | * For more details, see <netinet/ip_input.c>. | |
761 | */ | |
762 | ip_len = ip_len + (iph->ip_hl << 2); | |
7f57883e DS |
763 | #endif |
764 | ||
d62a17ae | 765 | #if defined(__DragonFly__) |
766 | /* | |
767 | * in DragonFly's raw socket, ip_len/ip_off are read | |
768 | * in network byte order. | |
769 | * As OpenBSD < 200311 adjust ip_len to strip IP header size! | |
770 | */ | |
771 | ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2); | |
7f57883e DS |
772 | #endif |
773 | ||
d62a17ae | 774 | ifindex = getsockopt_ifindex(AF_INET, &msgh); |
7f57883e | 775 | |
d62a17ae | 776 | *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); |
7f57883e | 777 | |
d62a17ae | 778 | if (ret != ip_len) { |
779 | zlog_warn( | |
780 | "eigrp_recv_packet read length mismatch: ip_len is %d, " | |
781 | "but recvmsg returned %d", | |
782 | ip_len, ret); | |
783 | return NULL; | |
784 | } | |
7f57883e | 785 | |
d62a17ae | 786 | return ibuf; |
7f57883e DS |
787 | } |
788 | ||
d62a17ae | 789 | struct eigrp_fifo *eigrp_fifo_new(void) |
7f57883e | 790 | { |
d62a17ae | 791 | struct eigrp_fifo *new; |
7f57883e | 792 | |
d62a17ae | 793 | new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo)); |
794 | return new; | |
7f57883e DS |
795 | } |
796 | ||
797 | /* Free eigrp packet fifo. */ | |
d62a17ae | 798 | void eigrp_fifo_free(struct eigrp_fifo *fifo) |
7f57883e | 799 | { |
d62a17ae | 800 | struct eigrp_packet *ep; |
801 | struct eigrp_packet *next; | |
802 | ||
803 | for (ep = fifo->head; ep; ep = next) { | |
804 | next = ep->next; | |
805 | eigrp_packet_free(ep); | |
806 | } | |
807 | fifo->head = fifo->tail = NULL; | |
808 | fifo->count = 0; | |
809 | ||
810 | XFREE(MTYPE_EIGRP_FIFO, fifo); | |
7f57883e DS |
811 | } |
812 | ||
813 | /* Free eigrp fifo entries without destroying fifo itself*/ | |
d62a17ae | 814 | void eigrp_fifo_reset(struct eigrp_fifo *fifo) |
7f57883e | 815 | { |
d62a17ae | 816 | struct eigrp_packet *ep; |
817 | struct eigrp_packet *next; | |
818 | ||
819 | for (ep = fifo->head; ep; ep = next) { | |
820 | next = ep->next; | |
821 | eigrp_packet_free(ep); | |
822 | } | |
823 | fifo->head = fifo->tail = NULL; | |
824 | fifo->count = 0; | |
7f57883e DS |
825 | } |
826 | ||
d62a17ae | 827 | struct eigrp_packet *eigrp_packet_new(size_t size) |
7f57883e | 828 | { |
d62a17ae | 829 | struct eigrp_packet *new; |
7f57883e | 830 | |
d62a17ae | 831 | new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet)); |
832 | new->s = stream_new(size); | |
833 | new->retrans_counter = 0; | |
7f57883e | 834 | |
d62a17ae | 835 | return new; |
7f57883e DS |
836 | } |
837 | ||
d62a17ae | 838 | void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr) |
7f57883e | 839 | { |
d62a17ae | 840 | struct eigrp_packet *ep; |
841 | ||
842 | ep = eigrp_fifo_tail(nbr->retrans_queue); | |
843 | ||
844 | if (ep) { | |
845 | struct eigrp_packet *duplicate; | |
846 | duplicate = eigrp_packet_duplicate(ep, nbr); | |
847 | /* Add packet to the top of the interface output queue*/ | |
848 | eigrp_fifo_push_head(nbr->ei->obuf, duplicate); | |
849 | ||
850 | /*Start retransmission timer*/ | |
851 | thread_add_timer(master, eigrp_unack_packet_retrans, nbr, | |
852 | EIGRP_PACKET_RETRANS_TIME, | |
853 | &ep->t_retrans_timer); | |
854 | ||
855 | /*Increment sequence number counter*/ | |
856 | nbr->ei->eigrp->sequence_number++; | |
857 | ||
858 | /* Hook thread to write packet. */ | |
859 | if (nbr->ei->on_write_q == 0) { | |
860 | listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei); | |
861 | nbr->ei->on_write_q = 1; | |
862 | } | |
863 | thread_add_write(master, eigrp_write, nbr->ei->eigrp, | |
864 | nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write); | |
865 | } | |
7f57883e DS |
866 | } |
867 | ||
868 | /* Calculate EIGRP checksum */ | |
d62a17ae | 869 | void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s, |
870 | u_int16_t length) | |
7f57883e | 871 | { |
d62a17ae | 872 | struct eigrp_header *eigrph; |
7f57883e | 873 | |
d62a17ae | 874 | eigrph = (struct eigrp_header *)STREAM_DATA(s); |
7f57883e | 875 | |
d62a17ae | 876 | /* Calculate checksum. */ |
877 | eigrph->checksum = in_cksum(eigrph, length); | |
7f57883e DS |
878 | } |
879 | ||
880 | /* Make EIGRP header. */ | |
d62a17ae | 881 | void eigrp_packet_header_init(int type, struct eigrp_interface *ei, |
882 | struct stream *s, u_int32_t flags, | |
883 | u_int32_t sequence, u_int32_t ack) | |
7f57883e | 884 | { |
d62a17ae | 885 | struct eigrp_header *eigrph; |
7f57883e | 886 | |
d62a17ae | 887 | eigrph = (struct eigrp_header *)STREAM_DATA(s); |
7f57883e | 888 | |
d62a17ae | 889 | eigrph->version = (u_char)EIGRP_HEADER_VERSION; |
890 | eigrph->opcode = (u_char)type; | |
891 | eigrph->checksum = 0; | |
7f57883e | 892 | |
d62a17ae | 893 | eigrph->vrid = htons(ei->eigrp->vrid); |
894 | eigrph->ASNumber = htons(ei->eigrp->AS); | |
895 | eigrph->ack = htonl(ack); | |
896 | eigrph->sequence = htonl(sequence); | |
897 | // if(flags == EIGRP_INIT_FLAG) | |
898 | // eigrph->sequence = htonl(3); | |
899 | eigrph->flags = htonl(flags); | |
7f57883e | 900 | |
d62a17ae | 901 | if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) |
902 | zlog_debug("Packet Header Init Seq [%u] Ack [%u]", | |
903 | htonl(eigrph->sequence), htonl(eigrph->ack)); | |
7f57883e | 904 | |
d62a17ae | 905 | stream_forward_endp(s, EIGRP_HEADER_LEN); |
7f57883e DS |
906 | } |
907 | ||
908 | /* Add new packet to head of fifo. */ | |
d62a17ae | 909 | void eigrp_fifo_push_head(struct eigrp_fifo *fifo, struct eigrp_packet *ep) |
7f57883e | 910 | { |
d62a17ae | 911 | ep->next = fifo->head; |
912 | ep->previous = NULL; | |
7f57883e | 913 | |
d62a17ae | 914 | if (fifo->tail == NULL) |
915 | fifo->tail = ep; | |
7f57883e | 916 | |
d62a17ae | 917 | if (fifo->count != 0) |
918 | fifo->head->previous = ep; | |
7f57883e | 919 | |
d62a17ae | 920 | fifo->head = ep; |
7f57883e | 921 | |
d62a17ae | 922 | fifo->count++; |
7f57883e DS |
923 | } |
924 | ||
925 | /* Return first fifo entry. */ | |
d62a17ae | 926 | struct eigrp_packet *eigrp_fifo_head(struct eigrp_fifo *fifo) |
7f57883e | 927 | { |
d62a17ae | 928 | return fifo->head; |
7f57883e DS |
929 | } |
930 | ||
931 | /* Return last fifo entry. */ | |
d62a17ae | 932 | struct eigrp_packet *eigrp_fifo_tail(struct eigrp_fifo *fifo) |
7f57883e | 933 | { |
d62a17ae | 934 | return fifo->tail; |
7f57883e DS |
935 | } |
936 | ||
d62a17ae | 937 | void eigrp_packet_delete(struct eigrp_interface *ei) |
7f57883e | 938 | { |
d62a17ae | 939 | struct eigrp_packet *ep; |
7f57883e | 940 | |
d62a17ae | 941 | ep = eigrp_fifo_pop(ei->obuf); |
7f57883e | 942 | |
d62a17ae | 943 | if (ep) |
944 | eigrp_packet_free(ep); | |
7f57883e DS |
945 | } |
946 | ||
947 | /* Delete first packet from fifo. */ | |
d62a17ae | 948 | struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo) |
7f57883e | 949 | { |
d62a17ae | 950 | struct eigrp_packet *ep; |
7f57883e | 951 | |
d62a17ae | 952 | ep = fifo->head; |
7f57883e | 953 | |
d62a17ae | 954 | if (ep) { |
955 | fifo->head = ep->next; | |
7f57883e | 956 | |
d62a17ae | 957 | if (fifo->head == NULL) |
958 | fifo->tail = NULL; | |
959 | else | |
960 | fifo->head->previous = NULL; | |
7f57883e | 961 | |
d62a17ae | 962 | fifo->count--; |
963 | } | |
7f57883e | 964 | |
d62a17ae | 965 | return ep; |
7f57883e DS |
966 | } |
967 | ||
d62a17ae | 968 | void eigrp_packet_free(struct eigrp_packet *ep) |
7f57883e | 969 | { |
d62a17ae | 970 | if (ep->s) |
971 | stream_free(ep->s); | |
7f57883e | 972 | |
d62a17ae | 973 | THREAD_OFF(ep->t_retrans_timer); |
7f57883e | 974 | |
d62a17ae | 975 | XFREE(MTYPE_EIGRP_PACKET, ep); |
7f57883e | 976 | |
d62a17ae | 977 | ep = NULL; |
7f57883e DS |
978 | } |
979 | ||
980 | /* EIGRP Header verification. */ | |
d62a17ae | 981 | static int eigrp_verify_header(struct stream *ibuf, struct eigrp_interface *ei, |
982 | struct ip *iph, struct eigrp_header *eigrph) | |
7f57883e | 983 | { |
d62a17ae | 984 | /* Check network mask, Silently discarded. */ |
985 | if (!eigrp_check_network_mask(ei, iph->ip_src)) { | |
986 | zlog_warn( | |
987 | "interface %s: eigrp_read network address is not same [%s]", | |
988 | IF_NAME(ei), inet_ntoa(iph->ip_src)); | |
989 | return -1; | |
990 | } | |
991 | // | |
992 | // /* Check authentication. The function handles logging actions, where | |
993 | // required. */ | |
994 | // if (! eigrp_check_auth(ei, eigrph)) | |
995 | // return -1; | |
996 | ||
997 | return 0; | |
7f57883e DS |
998 | } |
999 | ||
1000 | /* Unbound socket will accept any Raw IP packets if proto is matched. | |
f9e5c9ca DS |
1001 | To prevent it, compare src IP address and i/f address with masking |
1002 | i/f network mask. */ | |
d62a17ae | 1003 | static int eigrp_check_network_mask(struct eigrp_interface *ei, |
1004 | struct in_addr ip_src) | |
7f57883e | 1005 | { |
d62a17ae | 1006 | struct in_addr mask, me, him; |
7f57883e | 1007 | |
d62a17ae | 1008 | if (ei->type == EIGRP_IFTYPE_POINTOPOINT) |
1009 | return 1; | |
7f57883e | 1010 | |
d62a17ae | 1011 | masklen2ip(ei->address->prefixlen, &mask); |
7f57883e | 1012 | |
d62a17ae | 1013 | me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr; |
1014 | him.s_addr = ip_src.s_addr & mask.s_addr; | |
7f57883e | 1015 | |
d62a17ae | 1016 | if (IPV4_ADDR_SAME(&me, &him)) |
1017 | return 1; | |
7f57883e | 1018 | |
d62a17ae | 1019 | return 0; |
7f57883e DS |
1020 | } |
1021 | ||
d62a17ae | 1022 | int eigrp_unack_packet_retrans(struct thread *thread) |
7f57883e | 1023 | { |
d62a17ae | 1024 | struct eigrp_neighbor *nbr; |
1025 | nbr = (struct eigrp_neighbor *)THREAD_ARG(thread); | |
1026 | ||
1027 | struct eigrp_packet *ep; | |
1028 | ep = eigrp_fifo_tail(nbr->retrans_queue); | |
1029 | ||
1030 | if (ep) { | |
1031 | struct eigrp_packet *duplicate; | |
1032 | duplicate = eigrp_packet_duplicate(ep, nbr); | |
1033 | ||
1034 | /* Add packet to the top of the interface output queue*/ | |
1035 | eigrp_fifo_push_head(nbr->ei->obuf, duplicate); | |
1036 | ||
1037 | ep->retrans_counter++; | |
1038 | if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) | |
1039 | return eigrp_retrans_count_exceeded(ep, nbr); | |
1040 | ||
1041 | /*Start retransmission timer*/ | |
1042 | ep->t_retrans_timer = NULL; | |
1043 | thread_add_timer(master, eigrp_unack_packet_retrans, nbr, | |
1044 | EIGRP_PACKET_RETRANS_TIME, | |
1045 | &ep->t_retrans_timer); | |
1046 | ||
1047 | /* Hook thread to write packet. */ | |
1048 | if (nbr->ei->on_write_q == 0) { | |
1049 | listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei); | |
1050 | nbr->ei->on_write_q = 1; | |
1051 | } | |
1052 | thread_add_write(master, eigrp_write, nbr->ei->eigrp, | |
1053 | nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write); | |
1054 | } | |
1055 | ||
1056 | return 0; | |
7f57883e DS |
1057 | } |
1058 | ||
d62a17ae | 1059 | int eigrp_unack_multicast_packet_retrans(struct thread *thread) |
7f57883e | 1060 | { |
d62a17ae | 1061 | struct eigrp_neighbor *nbr; |
1062 | nbr = (struct eigrp_neighbor *)THREAD_ARG(thread); | |
1063 | ||
1064 | struct eigrp_packet *ep; | |
1065 | ep = eigrp_fifo_tail(nbr->multicast_queue); | |
1066 | ||
1067 | if (ep) { | |
1068 | struct eigrp_packet *duplicate; | |
1069 | duplicate = eigrp_packet_duplicate(ep, nbr); | |
1070 | /* Add packet to the top of the interface output queue*/ | |
1071 | eigrp_fifo_push_head(nbr->ei->obuf, duplicate); | |
1072 | ||
1073 | ep->retrans_counter++; | |
1074 | if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) | |
1075 | return eigrp_retrans_count_exceeded(ep, nbr); | |
1076 | ||
1077 | /*Start retransmission timer*/ | |
1078 | ep->t_retrans_timer = NULL; | |
1079 | thread_add_timer(master, eigrp_unack_multicast_packet_retrans, | |
1080 | nbr, EIGRP_PACKET_RETRANS_TIME, | |
1081 | &ep->t_retrans_timer); | |
1082 | ||
1083 | /* Hook thread to write packet. */ | |
1084 | if (nbr->ei->on_write_q == 0) { | |
1085 | listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei); | |
1086 | nbr->ei->on_write_q = 1; | |
1087 | } | |
1088 | thread_add_write(master, eigrp_write, nbr->ei->eigrp, | |
1089 | nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write); | |
1090 | } | |
1091 | ||
1092 | return 0; | |
7f57883e DS |
1093 | } |
1094 | ||
1095 | /* Get packet from tail of fifo. */ | |
d62a17ae | 1096 | struct eigrp_packet *eigrp_fifo_pop_tail(struct eigrp_fifo *fifo) |
7f57883e | 1097 | { |
d62a17ae | 1098 | struct eigrp_packet *ep; |
7f57883e | 1099 | |
d62a17ae | 1100 | ep = fifo->tail; |
7f57883e | 1101 | |
d62a17ae | 1102 | if (ep) { |
1103 | fifo->tail = ep->previous; | |
7f57883e | 1104 | |
d62a17ae | 1105 | if (fifo->tail == NULL) |
1106 | fifo->head = NULL; | |
1107 | else | |
1108 | fifo->tail->next = NULL; | |
7f57883e | 1109 | |
d62a17ae | 1110 | fifo->count--; |
1111 | } | |
7f57883e | 1112 | |
d62a17ae | 1113 | return ep; |
7f57883e DS |
1114 | } |
1115 | ||
d62a17ae | 1116 | struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old, |
1117 | struct eigrp_neighbor *nbr) | |
7f57883e | 1118 | { |
d62a17ae | 1119 | struct eigrp_packet *new; |
7f57883e | 1120 | |
d62a17ae | 1121 | new = eigrp_packet_new(nbr->ei->ifp->mtu); |
1122 | new->length = old->length; | |
1123 | new->retrans_counter = old->retrans_counter; | |
1124 | new->dst = old->dst; | |
1125 | new->sequence_number = old->sequence_number; | |
1126 | stream_copy(new->s, old->s); | |
7f57883e | 1127 | |
d62a17ae | 1128 | return new; |
7f57883e DS |
1129 | } |
1130 | ||
d62a17ae | 1131 | struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s) |
7f57883e | 1132 | { |
d62a17ae | 1133 | struct TLV_IPv4_Internal_type *tlv; |
1134 | ||
1135 | tlv = eigrp_IPv4_InternalTLV_new(); | |
1136 | ||
1137 | tlv->type = stream_getw(s); | |
1138 | tlv->length = stream_getw(s); | |
1139 | tlv->forward.s_addr = stream_getl(s); | |
1140 | tlv->metric.delay = stream_getl(s); | |
1141 | tlv->metric.bandwith = stream_getl(s); | |
1142 | tlv->metric.mtu[0] = stream_getc(s); | |
1143 | tlv->metric.mtu[1] = stream_getc(s); | |
1144 | tlv->metric.mtu[2] = stream_getc(s); | |
1145 | tlv->metric.hop_count = stream_getc(s); | |
1146 | tlv->metric.reliability = stream_getc(s); | |
1147 | tlv->metric.load = stream_getc(s); | |
1148 | tlv->metric.tag = stream_getc(s); | |
1149 | tlv->metric.flags = stream_getc(s); | |
1150 | ||
1151 | tlv->prefix_length = stream_getc(s); | |
1152 | ||
1153 | if (tlv->prefix_length <= 8) { | |
1154 | tlv->destination_part[0] = stream_getc(s); | |
1155 | tlv->destination.s_addr = (tlv->destination_part[0]); | |
1156 | } else if (tlv->prefix_length > 8 && tlv->prefix_length <= 16) { | |
1157 | tlv->destination_part[0] = stream_getc(s); | |
1158 | tlv->destination_part[1] = stream_getc(s); | |
1159 | tlv->destination.s_addr = ((tlv->destination_part[1] << 8) | |
1160 | + tlv->destination_part[0]); | |
1161 | } else if (tlv->prefix_length > 16 && tlv->prefix_length <= 24) { | |
1162 | tlv->destination_part[0] = stream_getc(s); | |
1163 | tlv->destination_part[1] = stream_getc(s); | |
1164 | tlv->destination_part[2] = stream_getc(s); | |
1165 | tlv->destination.s_addr = ((tlv->destination_part[2] << 16) | |
1166 | + (tlv->destination_part[1] << 8) | |
1167 | + tlv->destination_part[0]); | |
1168 | } else if (tlv->prefix_length > 24 && tlv->prefix_length <= 32) { | |
1169 | tlv->destination_part[0] = stream_getc(s); | |
1170 | tlv->destination_part[1] = stream_getc(s); | |
1171 | tlv->destination_part[2] = stream_getc(s); | |
1172 | tlv->destination_part[3] = stream_getc(s); | |
1173 | tlv->destination.s_addr = ((tlv->destination_part[3] << 24) | |
1174 | + (tlv->destination_part[2] << 16) | |
1175 | + (tlv->destination_part[1] << 8) | |
1176 | + tlv->destination_part[0]); | |
1177 | } | |
1178 | return tlv; | |
7f57883e DS |
1179 | } |
1180 | ||
d62a17ae | 1181 | u_int16_t eigrp_add_internalTLV_to_stream(struct stream *s, |
1182 | struct eigrp_prefix_entry *pe) | |
7f57883e | 1183 | { |
d62a17ae | 1184 | u_int16_t length; |
1185 | ||
1186 | stream_putw(s, EIGRP_TLV_IPv4_INT); | |
1187 | if (pe->destination_ipv4->prefixlen <= 8) { | |
1188 | stream_putw(s, 0x001A); | |
1189 | length = 0x001A; | |
1190 | } | |
1191 | if ((pe->destination_ipv4->prefixlen > 8) | |
1192 | && (pe->destination_ipv4->prefixlen <= 16)) { | |
1193 | stream_putw(s, 0x001B); | |
1194 | length = 0x001B; | |
1195 | } | |
1196 | if ((pe->destination_ipv4->prefixlen > 16) | |
1197 | && (pe->destination_ipv4->prefixlen <= 24)) { | |
1198 | stream_putw(s, 0x001C); | |
1199 | length = 0x001C; | |
1200 | } | |
1201 | if (pe->destination_ipv4->prefixlen > 24) { | |
1202 | stream_putw(s, 0x001D); | |
1203 | length = 0x001D; | |
1204 | } | |
1205 | ||
1206 | stream_putl(s, 0x00000000); | |
1207 | ||
1208 | /*Metric*/ | |
1209 | stream_putl(s, pe->reported_metric.delay); | |
1210 | stream_putl(s, pe->reported_metric.bandwith); | |
1211 | stream_putc(s, pe->reported_metric.mtu[2]); | |
1212 | stream_putc(s, pe->reported_metric.mtu[1]); | |
1213 | stream_putc(s, pe->reported_metric.mtu[0]); | |
1214 | stream_putc(s, pe->reported_metric.hop_count); | |
1215 | stream_putc(s, pe->reported_metric.reliability); | |
1216 | stream_putc(s, pe->reported_metric.load); | |
1217 | stream_putc(s, pe->reported_metric.tag); | |
1218 | stream_putc(s, pe->reported_metric.flags); | |
1219 | ||
1220 | stream_putc(s, pe->destination_ipv4->prefixlen); | |
1221 | ||
1222 | if (pe->destination_ipv4->prefixlen <= 8) { | |
1223 | stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); | |
1224 | } | |
1225 | if ((pe->destination_ipv4->prefixlen > 8) | |
1226 | && (pe->destination_ipv4->prefixlen <= 16)) { | |
1227 | stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); | |
1228 | stream_putc(s, | |
1229 | (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); | |
1230 | } | |
1231 | if ((pe->destination_ipv4->prefixlen > 16) | |
1232 | && (pe->destination_ipv4->prefixlen <= 24)) { | |
1233 | stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); | |
1234 | stream_putc(s, | |
1235 | (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); | |
1236 | stream_putc(s, | |
1237 | (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF); | |
1238 | } | |
1239 | if (pe->destination_ipv4->prefixlen > 24) { | |
1240 | stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); | |
1241 | stream_putc(s, | |
1242 | (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); | |
1243 | stream_putc(s, | |
1244 | (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF); | |
1245 | stream_putc(s, | |
1246 | (pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF); | |
1247 | } | |
1248 | ||
1249 | return length; | |
7f57883e DS |
1250 | } |
1251 | ||
d62a17ae | 1252 | u_int16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s, |
1253 | struct eigrp_interface *ei) | |
7f57883e | 1254 | { |
d62a17ae | 1255 | struct key *key; |
1256 | struct keychain *keychain; | |
1257 | struct TLV_MD5_Authentication_Type *authTLV; | |
1258 | ||
1259 | authTLV = eigrp_authTLV_MD5_new(); | |
1260 | ||
1261 | authTLV->type = htons(EIGRP_TLV_AUTH); | |
1262 | authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE); | |
1263 | authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5); | |
1264 | authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN); | |
1265 | authTLV->key_sequence = 0; | |
1266 | memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad)); | |
1267 | ||
1268 | keychain = keychain_lookup(IF_DEF_PARAMS(ei->ifp)->auth_keychain); | |
1269 | if (keychain) | |
1270 | key = key_lookup_for_send(keychain); | |
1271 | else { | |
1272 | free(IF_DEF_PARAMS(ei->ifp)->auth_keychain); | |
1273 | IF_DEF_PARAMS(ei->ifp)->auth_keychain = NULL; | |
1274 | eigrp_authTLV_MD5_free(authTLV); | |
1275 | return 0; | |
1276 | } | |
1277 | ||
1278 | if (key) { | |
1279 | authTLV->key_id = htonl(key->index); | |
1280 | memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_MD5_LEN); | |
1281 | stream_put(s, authTLV, | |
1282 | sizeof(struct TLV_MD5_Authentication_Type)); | |
1283 | eigrp_authTLV_MD5_free(authTLV); | |
1284 | return EIGRP_AUTH_MD5_TLV_SIZE; | |
1285 | } | |
1286 | ||
1287 | eigrp_authTLV_MD5_free(authTLV); | |
1288 | ||
1289 | return 0; | |
7f57883e DS |
1290 | } |
1291 | ||
d62a17ae | 1292 | u_int16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s, |
1293 | struct eigrp_interface *ei) | |
7f57883e | 1294 | { |
d62a17ae | 1295 | struct key *key; |
1296 | struct keychain *keychain; | |
1297 | struct TLV_SHA256_Authentication_Type *authTLV; | |
1298 | ||
1299 | authTLV = eigrp_authTLV_SHA256_new(); | |
1300 | ||
1301 | authTLV->type = htons(EIGRP_TLV_AUTH); | |
1302 | authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE); | |
1303 | authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256); | |
1304 | authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN); | |
1305 | authTLV->key_sequence = 0; | |
1306 | memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad)); | |
1307 | ||
1308 | keychain = keychain_lookup(IF_DEF_PARAMS(ei->ifp)->auth_keychain); | |
1309 | if (keychain) | |
1310 | key = key_lookup_for_send(keychain); | |
1311 | else { | |
1312 | free(IF_DEF_PARAMS(ei->ifp)->auth_keychain); | |
1313 | IF_DEF_PARAMS(ei->ifp)->auth_keychain = NULL; | |
1314 | eigrp_authTLV_SHA256_free(authTLV); | |
1315 | return 0; | |
1316 | } | |
1317 | ||
1318 | if (key) { | |
1319 | authTLV->key_id = 0; | |
1320 | memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_SHA256_LEN); | |
1321 | stream_put(s, authTLV, | |
1322 | sizeof(struct TLV_SHA256_Authentication_Type)); | |
1323 | eigrp_authTLV_SHA256_free(authTLV); | |
1324 | return EIGRP_AUTH_SHA256_TLV_SIZE; | |
1325 | } | |
1326 | ||
1327 | eigrp_authTLV_SHA256_free(authTLV); | |
1328 | ||
1329 | return 0; | |
7f57883e DS |
1330 | } |
1331 | ||
d62a17ae | 1332 | struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new() |
7f57883e | 1333 | { |
d62a17ae | 1334 | struct TLV_MD5_Authentication_Type *new; |
7f57883e | 1335 | |
d62a17ae | 1336 | new = XCALLOC(MTYPE_EIGRP_AUTH_TLV, |
1337 | sizeof(struct TLV_MD5_Authentication_Type)); | |
7f57883e | 1338 | |
d62a17ae | 1339 | return new; |
7f57883e DS |
1340 | } |
1341 | ||
d62a17ae | 1342 | void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV) |
7f57883e | 1343 | { |
d62a17ae | 1344 | XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV); |
7f57883e DS |
1345 | } |
1346 | ||
d62a17ae | 1347 | struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new() |
7f57883e | 1348 | { |
d62a17ae | 1349 | struct TLV_SHA256_Authentication_Type *new; |
7f57883e | 1350 | |
d62a17ae | 1351 | new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV, |
1352 | sizeof(struct TLV_SHA256_Authentication_Type)); | |
7f57883e | 1353 | |
d62a17ae | 1354 | return new; |
7f57883e DS |
1355 | } |
1356 | ||
d62a17ae | 1357 | void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV) |
7f57883e | 1358 | { |
d62a17ae | 1359 | XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV); |
7f57883e DS |
1360 | } |
1361 | ||
d62a17ae | 1362 | struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new() |
7f57883e | 1363 | { |
d62a17ae | 1364 | struct TLV_IPv4_Internal_type *new; |
7f57883e | 1365 | |
d62a17ae | 1366 | new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV, |
1367 | sizeof(struct TLV_IPv4_Internal_type)); | |
7f57883e | 1368 | |
d62a17ae | 1369 | return new; |
7f57883e DS |
1370 | } |
1371 | ||
d62a17ae | 1372 | void eigrp_IPv4_InternalTLV_free( |
1373 | struct TLV_IPv4_Internal_type *IPv4_InternalTLV) | |
7f57883e | 1374 | { |
d62a17ae | 1375 | XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV); |
7f57883e DS |
1376 | } |
1377 | ||
d62a17ae | 1378 | struct TLV_Sequence_Type *eigrp_SequenceTLV_new() |
7f57883e | 1379 | { |
d62a17ae | 1380 | struct TLV_Sequence_Type *new; |
7f57883e | 1381 | |
d62a17ae | 1382 | new = XCALLOC(MTYPE_EIGRP_SEQ_TLV, sizeof(struct TLV_Sequence_Type)); |
7f57883e | 1383 | |
d62a17ae | 1384 | return new; |
7f57883e | 1385 | } |