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