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