Annotation of embedaddon/bird2/proto/rip/packets.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- Routing Information Protocol (RIP)
! 3: *
! 4: * (c) 1998--1999 Pavel Machek <pavel@ucw.cz>
! 5: * (c) 2004--2013 Ondrej Filip <feela@network.cz>
! 6: * (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
! 7: * (c) 2009--2015 CZ.NIC z.s.p.o.
! 8: *
! 9: * Can be freely distributed and used under the terms of the GNU GPL.
! 10: */
! 11:
! 12: #undef LOCAL_DEBUG
! 13:
! 14: #include "rip.h"
! 15: #include "lib/mac.h"
! 16:
! 17:
! 18: #define RIP_CMD_REQUEST 1 /* want info */
! 19: #define RIP_CMD_RESPONSE 2 /* responding to request */
! 20:
! 21: #define RIP_BLOCK_LENGTH 20
! 22: #define RIP_PASSWD_LENGTH 16
! 23:
! 24: #define RIP_AF_IPV4 2
! 25: #define RIP_AF_AUTH 0xffff
! 26:
! 27:
! 28: /* RIP packet header */
! 29: struct rip_packet
! 30: {
! 31: u8 command;
! 32: u8 version;
! 33: u16 unused;
! 34: };
! 35:
! 36: /* RTE block for RIPv2 */
! 37: struct rip_block_v2
! 38: {
! 39: u16 family;
! 40: u16 tag;
! 41: ip4_addr network;
! 42: ip4_addr netmask;
! 43: ip4_addr next_hop;
! 44: u32 metric;
! 45: };
! 46:
! 47: /* RTE block for RIPng */
! 48: struct rip_block_ng
! 49: {
! 50: ip6_addr prefix;
! 51: u16 tag;
! 52: u8 pxlen;
! 53: u8 metric;
! 54: };
! 55:
! 56: /* Authentication block for RIPv2 */
! 57: struct rip_block_auth
! 58: {
! 59: u16 must_be_ffff;
! 60: u16 auth_type;
! 61: union {
! 62: char password[16];
! 63: struct {
! 64: u16 packet_len;
! 65: u8 key_id;
! 66: u8 auth_len;
! 67: u32 seq_num;
! 68: u32 unused1;
! 69: u32 unused2;
! 70: };
! 71: };
! 72: };
! 73:
! 74: /* Authentication tail, RFC 4822 */
! 75: struct rip_auth_tail
! 76: {
! 77: u16 must_be_ffff;
! 78: u16 must_be_0001;
! 79: byte auth_data[0];
! 80: };
! 81:
! 82: /* Internal representation of RTE block data */
! 83: struct rip_block
! 84: {
! 85: net_addr net;
! 86: u32 metric;
! 87: u16 tag;
! 88: u16 no_af;
! 89: ip_addr next_hop;
! 90: };
! 91:
! 92:
! 93: #define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
! 94: #define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0)
! 95: #define SKIP(DSC) do { err_dsc = DSC; goto skip; } while(0)
! 96:
! 97: #define LOG_PKT(msg, args...) \
! 98: log_rl(&p->log_pkt_tbf, L_REMOTE "%s: " msg, p->p.name, args)
! 99:
! 100: #define LOG_PKT_AUTH(msg, args...) \
! 101: log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args)
! 102:
! 103: #define LOG_RTE(msg, args...) \
! 104: log_rl(&p->log_rte_tbf, L_REMOTE "%s: " msg, p->p.name, args)
! 105:
! 106:
! 107: static inline void * rip_tx_buffer(struct rip_iface *ifa)
! 108: { return ifa->sk->tbuf; }
! 109:
! 110: static inline uint rip_pkt_hdrlen(struct rip_iface *ifa)
! 111: { return sizeof(struct rip_packet) + (ifa->cf->auth_type ? RIP_BLOCK_LENGTH : 0); }
! 112:
! 113: static inline void
! 114: rip_put_block(struct rip_proto *p, byte *pos, struct rip_block *rte)
! 115: {
! 116: if (rip_is_v2(p))
! 117: {
! 118: struct rip_block_v2 *block = (void *) pos;
! 119: block->family = rte->no_af ? 0 : htons(RIP_AF_IPV4);
! 120: block->tag = htons(rte->tag);
! 121: block->network = ip4_hton(net4_prefix(&rte->net));
! 122: block->netmask = ip4_hton(ip4_mkmask(net4_pxlen(&rte->net)));
! 123: block->next_hop = ip4_hton(ipa_to_ip4(rte->next_hop));
! 124: block->metric = htonl(rte->metric);
! 125: }
! 126: else /* RIPng */
! 127: {
! 128: struct rip_block_ng *block = (void *) pos;
! 129: block->prefix = ip6_hton(net6_prefix(&rte->net));
! 130: block->tag = htons(rte->tag);
! 131: block->pxlen = net6_pxlen(&rte->net);
! 132: block->metric = rte->metric;
! 133: }
! 134: }
! 135:
! 136: static inline void
! 137: rip_put_next_hop(struct rip_proto *p UNUSED, byte *pos, struct rip_block *rte)
! 138: {
! 139: struct rip_block_ng *block = (void *) pos;
! 140: block->prefix = ip6_hton(ipa_to_ip6(rte->next_hop));
! 141: block->tag = 0;
! 142: block->pxlen = 0;
! 143: block->metric = 0xff;
! 144: }
! 145:
! 146: static inline int
! 147: rip_get_block(struct rip_proto *p, byte *pos, struct rip_block *rte)
! 148: {
! 149: if (rip_is_v2(p))
! 150: {
! 151: struct rip_block_v2 *block = (void *) pos;
! 152:
! 153: /* Skip blocks with strange AF, including authentication blocks */
! 154: if (block->family != (rte->no_af ? 0 : htons(RIP_AF_IPV4)))
! 155: return 0;
! 156:
! 157: uint pxlen = ip4_masklen(ip4_ntoh(block->netmask));
! 158: net_fill_ip4(&rte->net, ip4_ntoh(block->network), pxlen);
! 159: rte->metric = ntohl(block->metric);
! 160: rte->tag = ntohs(block->tag);
! 161: rte->next_hop = ipa_from_ip4(ip4_ntoh(block->next_hop));
! 162:
! 163: return 1;
! 164: }
! 165: else /* RIPng */
! 166: {
! 167: struct rip_block_ng *block = (void *) pos;
! 168:
! 169: /* Handle and skip next hop blocks */
! 170: if (block->metric == 0xff)
! 171: {
! 172: rte->next_hop = ipa_from_ip6(ip6_ntoh(block->prefix));
! 173: if (!ipa_is_link_local(rte->next_hop)) rte->next_hop = IPA_NONE;
! 174: return 0;
! 175: }
! 176:
! 177: uint pxlen = (block->pxlen <= IP6_MAX_PREFIX_LENGTH) ? block->pxlen : 255;
! 178: net_fill_ip6(&rte->net, ip6_ntoh(block->prefix), pxlen);
! 179: rte->metric = block->metric;
! 180: rte->tag = ntohs(block->tag);
! 181: /* rte->next_hop is deliberately kept unmodified */;
! 182:
! 183: return 1;
! 184: }
! 185: }
! 186:
! 187: static inline void
! 188: rip_update_csn(struct rip_proto *p UNUSED, struct rip_iface *ifa)
! 189: {
! 190: /*
! 191: * We update crypto sequence numbers at the beginning of update session to
! 192: * avoid issues with packet reordering, so packets inside one update session
! 193: * have the same CSN. We are using real time, but enforcing monotonicity.
! 194: */
! 195: if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
! 196: {
! 197: u32 now_real = (u32) (current_real_time() TO_S);
! 198: ifa->csn = (ifa->csn < now_real) ? now_real : ifa->csn + 1;
! 199: }
! 200: }
! 201:
! 202: static void
! 203: rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen)
! 204: {
! 205: struct rip_block_auth *auth = (void *) (pkt + 1);
! 206: struct password_item *pass = password_find(ifa->cf->passwords, 0);
! 207:
! 208: if (!pass)
! 209: {
! 210: /* FIXME: This should not happen */
! 211: log(L_ERR "%s: No suitable password found for authentication", p->p.name);
! 212: memset(auth, 0, sizeof(struct rip_block_auth));
! 213: return;
! 214: }
! 215:
! 216: switch (ifa->cf->auth_type)
! 217: {
! 218: case RIP_AUTH_PLAIN:
! 219: auth->must_be_ffff = htons(0xffff);
! 220: auth->auth_type = htons(RIP_AUTH_PLAIN);
! 221: strncpy(auth->password, pass->password, RIP_PASSWD_LENGTH);
! 222: return;
! 223:
! 224: case RIP_AUTH_CRYPTO:
! 225: auth->must_be_ffff = htons(0xffff);
! 226: auth->auth_type = htons(RIP_AUTH_CRYPTO);
! 227: auth->packet_len = htons(*plen);
! 228: auth->key_id = pass->id;
! 229: auth->auth_len = mac_type_length(pass->alg);
! 230: auth->seq_num = ifa->csn_ready ? htonl(ifa->csn) : 0;
! 231: auth->unused1 = 0;
! 232: auth->unused2 = 0;
! 233: ifa->csn_ready = 1;
! 234:
! 235: if (pass->alg < ALG_HMAC)
! 236: auth->auth_len += sizeof(struct rip_auth_tail);
! 237:
! 238: /*
! 239: * Note that RFC 4822 is unclear whether auth_len should cover whole
! 240: * authentication trailer or just auth_data length.
! 241: *
! 242: * FIXME: We should use just auth_data length by default. Currently we put
! 243: * the whole auth trailer length in keyed hash case to keep old behavior,
! 244: * but we put just auth_data length in the new HMAC case. Note that Quagga
! 245: * has config option for this.
! 246: *
! 247: * Crypto sequence numbers are increased by sender in rip_update_csn().
! 248: * First CSN should be zero, this is handled by csn_ready.
! 249: */
! 250:
! 251: struct rip_auth_tail *tail = (void *) ((byte *) pkt + *plen);
! 252: tail->must_be_ffff = htons(0xffff);
! 253: tail->must_be_0001 = htons(0x0001);
! 254:
! 255: uint auth_len = mac_type_length(pass->alg);
! 256: *plen += sizeof(struct rip_auth_tail) + auth_len;
! 257:
! 258: /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
! 259: if (pass->alg < ALG_HMAC)
! 260: strncpy(tail->auth_data, pass->password, auth_len);
! 261: else
! 262: memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4);
! 263:
! 264: mac_fill(pass->alg, pass->password, pass->length,
! 265: (byte *) pkt, *plen, tail->auth_data);
! 266: return;
! 267:
! 268: default:
! 269: bug("Unknown authentication type");
! 270: }
! 271: }
! 272:
! 273: static int
! 274: rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen, struct rip_neighbor *n)
! 275: {
! 276: struct rip_block_auth *auth = (void *) (pkt + 1);
! 277: struct password_item *pass = NULL;
! 278: const char *err_dsc = NULL;
! 279: uint err_val = 0;
! 280: uint auth_type = 0;
! 281:
! 282: /* Check for authentication entry */
! 283: if ((*plen >= (sizeof(struct rip_packet) + sizeof(struct rip_block_auth))) &&
! 284: (auth->must_be_ffff == htons(0xffff)))
! 285: auth_type = ntohs(auth->auth_type);
! 286:
! 287: if (auth_type != ifa->cf->auth_type)
! 288: DROP("authentication method mismatch", auth_type);
! 289:
! 290: switch (auth_type)
! 291: {
! 292: case RIP_AUTH_NONE:
! 293: return 1;
! 294:
! 295: case RIP_AUTH_PLAIN:
! 296: pass = password_find_by_value(ifa->cf->passwords, auth->password, RIP_PASSWD_LENGTH);
! 297: if (!pass)
! 298: DROP1("wrong password");
! 299:
! 300: return 1;
! 301:
! 302: case RIP_AUTH_CRYPTO:
! 303: pass = password_find_by_id(ifa->cf->passwords, auth->key_id);
! 304: if (!pass)
! 305: DROP("no suitable password found", auth->key_id);
! 306:
! 307: uint data_len = ntohs(auth->packet_len);
! 308: uint auth_len = mac_type_length(pass->alg);
! 309: uint auth_len2 = sizeof(struct rip_auth_tail) + auth_len;
! 310:
! 311: /*
! 312: * Ideally, first check should be check for internal consistency:
! 313: * (data_len + sizeof(struct rip_auth_tail) + auth->auth_len) != *plen
! 314: *
! 315: * Second one should check expected code length:
! 316: * auth->auth_len != auth_len
! 317: *
! 318: * But as auth->auth_len has two interpretations, we simplify this
! 319: */
! 320:
! 321: if (data_len + auth_len2 != *plen)
! 322: DROP("packet length mismatch", *plen);
! 323:
! 324: /* Warning: two interpretations of auth_len field */
! 325: if ((auth->auth_len != auth_len) && (auth->auth_len != auth_len2))
! 326: DROP("wrong authentication length", auth->auth_len);
! 327:
! 328: struct rip_auth_tail *tail = (void *) ((byte *) pkt + data_len);
! 329: if ((tail->must_be_ffff != htons(0xffff)) || (tail->must_be_0001 != htons(0x0001)))
! 330: DROP1("authentication trailer is missing");
! 331:
! 332: /* Accept higher sequence number, or zero if connectivity is lost */
! 333: /* FIXME: sequence number must be password/SA specific */
! 334: u32 rcv_csn = ntohl(auth->seq_num);
! 335: if ((rcv_csn < n->csn) && (rcv_csn || n->uc))
! 336: {
! 337: /* We want to report both new and old CSN */
! 338: LOG_PKT_AUTH("Authentication failed for %I on %s - "
! 339: "lower sequence number (rcv %u, old %u)",
! 340: n->nbr->addr, ifa->iface->name, rcv_csn, n->csn);
! 341: return 0;
! 342: }
! 343:
! 344: byte *auth_data = alloca(auth_len);
! 345: memcpy(auth_data, tail->auth_data, auth_len);
! 346:
! 347: /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
! 348: if (pass->alg < ALG_HMAC)
! 349: strncpy(tail->auth_data, pass->password, auth_len);
! 350: else
! 351: memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4);
! 352:
! 353: if (!mac_verify(pass->alg, pass->password, pass->length,
! 354: (byte *) pkt, *plen, auth_data))
! 355: DROP("wrong authentication code", pass->id);
! 356:
! 357: *plen = data_len;
! 358: n->csn = rcv_csn;
! 359:
! 360: return 1;
! 361: }
! 362:
! 363: drop:
! 364: LOG_PKT_AUTH("Authentication failed for %I on %s - %s (%u)",
! 365: n->nbr->addr, ifa->iface->name, err_dsc, err_val);
! 366:
! 367: return 0;
! 368: }
! 369:
! 370: static inline int
! 371: rip_send_to(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint plen, ip_addr dst)
! 372: {
! 373: if (ifa->cf->auth_type)
! 374: rip_fill_authentication(p, ifa, pkt, &plen);
! 375:
! 376: return sk_send_to(ifa->sk, plen, dst, 0);
! 377: }
! 378:
! 379:
! 380: void
! 381: rip_send_request(struct rip_proto *p, struct rip_iface *ifa)
! 382: {
! 383: byte *pos = rip_tx_buffer(ifa);
! 384:
! 385: struct rip_packet *pkt = (void *) pos;
! 386: pkt->command = RIP_CMD_REQUEST;
! 387: pkt->version = ifa->cf->version;
! 388: pkt->unused = 0;
! 389: pos += rip_pkt_hdrlen(ifa);
! 390:
! 391: struct rip_block b = { .no_af = 1, .metric = p->infinity };
! 392: rip_put_block(p, pos, &b);
! 393: pos += RIP_BLOCK_LENGTH;
! 394:
! 395: rip_update_csn(p, ifa);
! 396:
! 397: TRACE(D_PACKETS, "Sending request via %s", ifa->iface->name);
! 398: rip_send_to(p, ifa, pkt, pos - (byte *) pkt, ifa->addr);
! 399: }
! 400:
! 401: static void
! 402: rip_receive_request(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint plen, struct rip_neighbor *from)
! 403: {
! 404: TRACE(D_PACKETS, "Request received from %I on %s", from->nbr->addr, ifa->iface->name);
! 405:
! 406: byte *pos = (byte *) pkt + rip_pkt_hdrlen(ifa);
! 407:
! 408: /* We expect one regular block */
! 409: if (plen != (rip_pkt_hdrlen(ifa) + RIP_BLOCK_LENGTH))
! 410: return;
! 411:
! 412: struct rip_block b = { .no_af = 1 };
! 413:
! 414: if (!rip_get_block(p, pos, &b))
! 415: return;
! 416:
! 417: /* Special case - infinity metric, for RIPng also zero prefix */
! 418: if ((b.metric != p->infinity) ||
! 419: (rip_is_ng(p) && !net_zero_ip6((net_addr_ip6 *) &b.net)))
! 420: return;
! 421:
! 422: /* We do nothing if TX is already active */
! 423: if (ifa->tx_active)
! 424: {
! 425: TRACE(D_EVENTS, "Skipping request from %I on %s, TX is busy", from->nbr->addr, ifa->iface->name);
! 426: return;
! 427: }
! 428:
! 429: if (!ifa->cf->passive)
! 430: rip_send_table(p, ifa, from->nbr->addr, 0);
! 431: }
! 432:
! 433:
! 434: static int
! 435: rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
! 436: {
! 437: if (! ifa->tx_active)
! 438: return 0;
! 439:
! 440: byte *pos = rip_tx_buffer(ifa);
! 441: byte *max = rip_tx_buffer(ifa) + ifa->tx_plen -
! 442: (rip_is_v2(p) ? RIP_BLOCK_LENGTH : 2*RIP_BLOCK_LENGTH);
! 443: ip_addr last_next_hop = IPA_NONE;
! 444: btime now_ = current_time();
! 445: int send = 0;
! 446:
! 447: struct rip_packet *pkt = (void *) pos;
! 448: pkt->command = RIP_CMD_RESPONSE;
! 449: pkt->version = ifa->cf->version;
! 450: pkt->unused = 0;
! 451: pos += rip_pkt_hdrlen(ifa);
! 452:
! 453: FIB_ITERATE_START(&p->rtable, &ifa->tx_fit, struct rip_entry, en)
! 454: {
! 455: /* Dummy entries */
! 456: if (!en->valid)
! 457: goto next_entry;
! 458:
! 459: /* Stale entries that should be removed */
! 460: if ((en->valid == RIP_ENTRY_STALE) &&
! 461: ((en->changed + ifa->cf->garbage_time) <= now_))
! 462: goto next_entry;
! 463:
! 464: /* Triggered updates */
! 465: if (en->changed < ifa->tx_changed)
! 466: goto next_entry;
! 467:
! 468: /* Not enough space for current entry */
! 469: if (pos > max)
! 470: {
! 471: FIB_ITERATE_PUT(&ifa->tx_fit);
! 472: goto break_loop;
! 473: }
! 474:
! 475: struct rip_block rte = {
! 476: .metric = en->metric,
! 477: .tag = en->tag
! 478: };
! 479:
! 480: net_copy(&rte.net, en->n.addr);
! 481:
! 482: if (en->iface == ifa->iface)
! 483: rte.next_hop = en->next_hop;
! 484:
! 485: if (rip_is_v2(p) && (ifa->cf->version == RIP_V1))
! 486: {
! 487: /* Skipping subnets (i.e. not hosts, classful networks or default route) */
! 488: if (ip4_masklen(ip4_class_mask(net4_prefix(&rte.net))) != rte.net.pxlen)
! 489: goto next_entry;
! 490:
! 491: rte.tag = 0;
! 492: rte.net.pxlen = 0;
! 493: rte.next_hop = IPA_NONE;
! 494: }
! 495:
! 496: /* Split horizon */
! 497: if (en->from == ifa->iface && ifa->cf->split_horizon)
! 498: {
! 499: if (ifa->cf->poison_reverse)
! 500: {
! 501: rte.metric = p->infinity;
! 502: rte.next_hop = IPA_NONE;
! 503: }
! 504: else
! 505: goto next_entry;
! 506: }
! 507:
! 508: // TRACE(D_PACKETS, " %N -> %I metric %d", &rte.net, rte.next_hop, rte.metric);
! 509:
! 510: /* RIPng next hop entry */
! 511: if (rip_is_ng(p) && !ipa_equal(rte.next_hop, last_next_hop))
! 512: {
! 513: last_next_hop = rte.next_hop;
! 514: rip_put_next_hop(p, pos, &rte);
! 515: pos += RIP_BLOCK_LENGTH;
! 516: }
! 517:
! 518: rip_put_block(p, pos, &rte);
! 519: pos += RIP_BLOCK_LENGTH;
! 520: send = 1;
! 521:
! 522: next_entry: ;
! 523: }
! 524: FIB_ITERATE_END;
! 525: ifa->tx_active = 0;
! 526:
! 527: /* Do not send empty packet */
! 528: if (!send)
! 529: return 0;
! 530:
! 531: break_loop:
! 532: TRACE(D_PACKETS, "Sending response via %s", ifa->iface->name);
! 533: return rip_send_to(p, ifa, pkt, pos - (byte *) pkt, ifa->tx_addr);
! 534: }
! 535:
! 536: /**
! 537: * rip_send_table - RIP interface timer hook
! 538: * @p: RIP instance
! 539: * @ifa: RIP interface
! 540: * @addr: destination IP address
! 541: * @changed: time limit for triggered updates
! 542: *
! 543: * The function activates an update session and starts sending routing update
! 544: * packets (using rip_send_response()). The session may be finished during the
! 545: * call or may continue in rip_tx_hook() until all appropriate routes are
! 546: * transmitted. Note that there may be at most one active update session per
! 547: * interface, the function will terminate the old active session before
! 548: * activating the new one.
! 549: */
! 550: void
! 551: rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed)
! 552: {
! 553: DBG("RIP: Opening TX session to %I on %s\n", addr, ifa->iface->name);
! 554:
! 555: rip_reset_tx_session(p, ifa);
! 556:
! 557: ifa->tx_active = 1;
! 558: ifa->tx_addr = addr;
! 559: ifa->tx_changed = changed;
! 560: FIB_ITERATE_INIT(&ifa->tx_fit, &p->rtable);
! 561:
! 562: rip_update_csn(p, ifa);
! 563:
! 564: while (rip_send_response(p, ifa) > 0)
! 565: ;
! 566: }
! 567:
! 568: static void
! 569: rip_tx_hook(sock *sk)
! 570: {
! 571: struct rip_iface *ifa = sk->data;
! 572: struct rip_proto *p = ifa->rip;
! 573:
! 574: DBG("RIP: TX hook called (iface %s, src %I, dst %I)\n",
! 575: sk->iface->name, sk->saddr, sk->daddr);
! 576:
! 577: while (rip_send_response(p, ifa) > 0)
! 578: ;
! 579: }
! 580:
! 581: static void
! 582: rip_err_hook(sock *sk, int err)
! 583: {
! 584: struct rip_iface *ifa = sk->data;
! 585: struct rip_proto *p = ifa->rip;
! 586:
! 587: log(L_ERR "%s: Socket error on %s: %M", p->p.name, ifa->iface->name, err);
! 588:
! 589: rip_reset_tx_session(p, ifa);
! 590: }
! 591:
! 592: static void
! 593: rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint plen, struct rip_neighbor *from)
! 594: {
! 595: struct rip_block rte = {};
! 596: const char *err_dsc = NULL;
! 597:
! 598: TRACE(D_PACKETS, "Response received from %I on %s", from->nbr->addr, ifa->iface->name);
! 599:
! 600: byte *pos = (byte *) pkt + sizeof(struct rip_packet);
! 601: byte *end = (byte *) pkt + plen;
! 602: btime now_ = current_time();
! 603:
! 604: for (; pos < end; pos += RIP_BLOCK_LENGTH)
! 605: {
! 606: /* Find next regular RTE */
! 607: if (!rip_get_block(p, pos, &rte))
! 608: continue;
! 609:
! 610: if (rip_is_v2(p) && (pkt->version == RIP_V1))
! 611: {
! 612: if (ifa->cf->check_zero && (rte.tag || rte.net.pxlen || ipa_nonzero(rte.next_hop)))
! 613: SKIP("RIPv1 reserved field is nonzero");
! 614:
! 615: rte.tag = 0;
! 616: rte.net.pxlen = ip4_masklen(ip4_class_mask(net4_prefix(&rte.net)));
! 617: rte.next_hop = IPA_NONE;
! 618: }
! 619:
! 620: if (rte.net.pxlen == 255)
! 621: SKIP("invalid prefix length");
! 622:
! 623: net_normalize(&rte.net);
! 624:
! 625: int c = net_classify(&rte.net);
! 626: if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
! 627: SKIP("invalid prefix");
! 628:
! 629: if (rte.metric > p->infinity)
! 630: SKIP("invalid metric");
! 631:
! 632: if (ipa_nonzero(rte.next_hop))
! 633: {
! 634: neighbor *nbr = neigh_find(&p->p, rte.next_hop, ifa->iface, 0);
! 635: if (!nbr || (nbr->scope <= 0))
! 636: rte.next_hop = IPA_NONE;
! 637: }
! 638:
! 639: // TRACE(D_PACKETS, " %N -> %I metric %d", &rte.net.n, rte.next_hop, rte.metric);
! 640:
! 641: rte.metric += ifa->cf->metric;
! 642:
! 643: if (rte.metric < p->infinity)
! 644: {
! 645: struct rip_rte new = {
! 646: .from = from,
! 647: .next_hop = ipa_nonzero(rte.next_hop) ? rte.next_hop : from->nbr->addr,
! 648: .metric = rte.metric,
! 649: .tag = rte.tag,
! 650: .expires = now_ + ifa->cf->timeout_time
! 651: };
! 652:
! 653: rip_update_rte(p, &rte.net, &new);
! 654: }
! 655: else
! 656: rip_withdraw_rte(p, &rte.net, from);
! 657:
! 658: continue;
! 659:
! 660: skip:
! 661: LOG_RTE("Ignoring route %N received from %I - %s",
! 662: &rte.net, from->nbr->addr, err_dsc);
! 663: }
! 664: }
! 665:
! 666: static int
! 667: rip_rx_hook(sock *sk, uint len)
! 668: {
! 669: struct rip_iface *ifa = sk->data;
! 670: struct rip_proto *p = ifa->rip;
! 671: const char *err_dsc = NULL;
! 672: uint err_val = 0;
! 673:
! 674: if (sk->lifindex != sk->iface->index)
! 675: return 1;
! 676:
! 677: DBG("RIP: RX hook called (iface %s, src %I, dst %I)\n",
! 678: sk->iface->name, sk->faddr, sk->laddr);
! 679:
! 680: /* Silently ignore my own packets */
! 681: if (ipa_equal(sk->faddr, sk->saddr))
! 682: return 1;
! 683:
! 684: if (rip_is_ng(p) && !ipa_is_link_local(sk->faddr))
! 685: DROP1("wrong src address");
! 686:
! 687: struct rip_neighbor *n = rip_get_neighbor(p, &sk->faddr, ifa);
! 688:
! 689: if (!n)
! 690: DROP1("not from neighbor");
! 691:
! 692: if ((ifa->cf->ttl_security == 1) && (sk->rcv_ttl < 255))
! 693: DROP("wrong TTL", sk->rcv_ttl);
! 694:
! 695: if (sk->fport != sk->dport)
! 696: DROP("wrong src port", sk->fport);
! 697:
! 698: if (len < sizeof(struct rip_packet))
! 699: DROP("too short", len);
! 700:
! 701: if (sk->flags & SKF_TRUNCATED)
! 702: DROP("truncated", len);
! 703:
! 704: struct rip_packet *pkt = (struct rip_packet *) sk->rbuf;
! 705: uint plen = len;
! 706:
! 707: if (!pkt->version || (ifa->cf->version_only && (pkt->version != ifa->cf->version)))
! 708: DROP("wrong version", pkt->version);
! 709:
! 710: /* rip_check_authentication() has its own error logging */
! 711: if (rip_is_v2(p) && !rip_check_authentication(p, ifa, pkt, &plen, n))
! 712: return 1;
! 713:
! 714: if ((plen - sizeof(struct rip_packet)) % RIP_BLOCK_LENGTH)
! 715: DROP("invalid length", plen);
! 716:
! 717: n->last_seen = current_time();
! 718: rip_update_bfd(p, n);
! 719:
! 720: switch (pkt->command)
! 721: {
! 722: case RIP_CMD_REQUEST:
! 723: rip_receive_request(p, ifa, pkt, plen, n);
! 724: break;
! 725:
! 726: case RIP_CMD_RESPONSE:
! 727: rip_receive_response(p, ifa, pkt, plen, n);
! 728: break;
! 729:
! 730: default:
! 731: DROP("unknown command", pkt->command);
! 732: }
! 733: return 1;
! 734:
! 735: drop:
! 736: LOG_PKT("Bad packet from %I via %s - %s (%u)",
! 737: sk->faddr, sk->iface->name, err_dsc, err_val);
! 738:
! 739: return 1;
! 740: }
! 741:
! 742: int
! 743: rip_open_socket(struct rip_iface *ifa)
! 744: {
! 745: struct rip_proto *p = ifa->rip;
! 746:
! 747: sock *sk = sk_new(p->p.pool);
! 748: sk->type = SK_UDP;
! 749: sk->subtype = rip_is_v2(p) ? SK_IPV4 : SK_IPV6;
! 750: sk->sport = ifa->cf->port;
! 751: sk->dport = ifa->cf->port;
! 752: sk->iface = ifa->iface;
! 753: sk->saddr = rip_is_v2(p) ? ifa->iface->addr4->ip : ifa->iface->llv6->ip;
! 754: sk->vrf = p->p.vrf;
! 755:
! 756: sk->rx_hook = rip_rx_hook;
! 757: sk->tx_hook = rip_tx_hook;
! 758: sk->err_hook = rip_err_hook;
! 759: sk->data = ifa;
! 760:
! 761: sk->tos = ifa->cf->tx_tos;
! 762: sk->priority = ifa->cf->tx_priority;
! 763: sk->ttl = ifa->cf->ttl_security ? 255 : 1;
! 764: sk->flags = SKF_LADDR_RX | ((ifa->cf->ttl_security == 1) ? SKF_TTL_RX : 0);
! 765:
! 766: /* sk->rbsize and sk->tbsize are handled in rip_iface_update_buffers() */
! 767:
! 768: if (sk_open(sk) < 0)
! 769: goto err;
! 770:
! 771: if (ifa->cf->mode == RIP_IM_MULTICAST)
! 772: {
! 773: if (sk_setup_multicast(sk) < 0)
! 774: goto err;
! 775:
! 776: if (sk_join_group(sk, ifa->addr) < 0)
! 777: goto err;
! 778: }
! 779: else /* Broadcast */
! 780: {
! 781: if (sk_setup_broadcast(sk) < 0)
! 782: goto err;
! 783:
! 784: if (ipa_zero(ifa->addr))
! 785: {
! 786: sk->err = "Missing broadcast address";
! 787: goto err;
! 788: }
! 789: }
! 790:
! 791: ifa->sk = sk;
! 792: return 1;
! 793:
! 794: err:
! 795: sk_log_error(sk, p->p.name);
! 796: rfree(sk);
! 797: return 0;
! 798: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>