1/* ICMP Router Discovery Messages 2 * Copyright (C) 1997, 2000 Kunihiro Ishiguro 3 * 4 * This file is part of GNU Zebra. 5 * 6 * GNU Zebra is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2, or (at your option) any 9 * later version. 10 * 11 * GNU Zebra is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with GNU Zebra; see the file COPYING. If not, write to the Free 18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 * 02111-1307, USA. 20 */ 21 22#include <zebra.h> 23 24#include <netinet/ip_icmp.h> 25 26#include "if.h" 27#include "stream.h" 28#include "memory.h" 29#include "command.h" 30#include "log.h" 31#include "sockunion.h" 32#include "sockopt.h" 33 34#include "zebra/irdp.h" 35 36/* Default does nothing. */ 37int irdp_mode = IRDP_NONE; 38 39/* Timer interval of irdp. */ 40int irdp_timer_interval = IRDP_DEFAULT_INTERVAL; 41 42/* Max solicitations */ 43int max_solicitations = MAX_SOLICITATIONS; 44 45#define IRDP_SOLICIT_PACKET_SIZE 8 46 47static struct irdp *irdp_head = NULL; 48 49extern int in_cksum (void *ptr, int nbytes); 50 51char *icmp_type_str[] = 52{ 53 "Echo Reply", 54 "ICMP 1", 55 "ICMP 2", 56 "Dest Unreachable", 57 "Source Quench", 58 "Redirect", 59 "ICMP 6", 60 "ICMP 7", 61 "Echo", 62 "Router Advertise", 63 "Router Solicitation", 64 "Time Exceeded", 65 "Parameter Problem", 66 "Timestamp", 67 "Timestamp Reply", 68 "Info Request", 69 "Info Reply", 70 "Netmask Request", 71 "Netmask Reply", 72}; 73 74char * 75icmp_type (int type) 76{ 77 if (type < 0 || type >= (sizeof icmp_type_str / sizeof (char *))) { 78 return "OUT-OF-RANGE"; 79 } 80 return icmp_type_str [type]; 81} 82 83/* */ 84void 85irdp_add_interface () 86{ 87 ; 88} 89 90/* */ 91void 92irdp_delete_interface () 93{ 94 95} 96 97struct irdp * 98irdp_route_new () 99{ 100 struct irdp *new = XMALLOC (0, sizeof (struct irdp)); 101 memset (new, 0, sizeof (struct irdp)); 102 return new; 103} 104 105void 106irdp_route_free (struct irdp *route) 107{ 108 XFREE (0, route); 109} 110 111void 112route_delete () 113{ 114 115} 116 117void 118route_init () 119{ 120 121} 122 123void 124route_add (struct in_addr addr, unsigned long pref) 125{ 126 struct irdp *new = irdp_route_new(); 127 128 new->prefix = addr; 129 new->pref = pref; 130 131 printf ("address %s\n", inet_ntoa (new->prefix)); 132 printf ("pref %ld\n", new->pref); 133} 134 135void 136route_age (int time) 137{ 138 struct irdp *p; 139 140 for (p = irdp_head; p != NULL; p = p->next) { 141 if (p->timer < time) { 142 /* fire */ 143 } else { 144 p->timer -= time; 145 } 146 } 147} 148 149#define FLAG_TEST(a) ((ifp->flags & (a)) == (a)) 150 151void 152send_multicast (struct interface *ifp, int sock, struct stream *s, int size) 153{ 154 struct sockaddr_in sin; 155 struct in_addr addr; 156 int nbytes; 157 struct connected *connected; 158 listnode node; 159 160 for (node = listhead (ifp->connected); node; nextnode (node)) 161 { 162 connected = getdata (node); 163 } 164 165 if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, 166 addr, 0, ifp->ifindex) < 0) 167 { 168 perror ("setsockopt"); 169 exit (1); 170 } 171 172 sin.sin_addr.s_addr = htonl (INADDR_ALLRTRS_GROUP); 173 sin.sin_family = AF_INET; 174 175 nbytes = sendto (sock, s->data, size, 0, 176 (struct sockaddr *) &sin, sizeof (struct sockaddr)); 177 178 if (nbytes != size) 179 { 180 perror ("sendto"); 181 exit (1); 182 } 183} 184 185void 186send_broadcast () 187{ 188 struct sockaddr_in sin; 189 190 printf ("broadcast\n"); 191 inet_aton ("255.255.255.255", &sin.sin_addr); 192} 193 194void 195irdp_send_solicit (int sock, struct stream *s, int size) 196{ 197 struct interface *ifp; 198 listnode node; 199 200 for (node = listhead (iflist); node; nextnode (node)) 201 { 202 ifp = getdata (node); 203 if (FLAG_TEST (IFF_UP | IFF_MULTICAST)) 204 { 205 send_multicast (ifp, sock, s, size); 206 } 207 else if (FLAG_TEST (IFF_UP | IFF_BROADCAST)) 208 { 209 send_broadcast (); 210 } 211 } 212} 213 214int 215ipv4_multicast_join (int sock, 216 struct in_addr group, 217 struct in_addr ifa, 218 unsigned int ifindex) 219{ 220 int ret; 221 222 ret = setsockopt_multicast_ipv4 (sock, IP_ADD_MEMBERSHIP, 223 ifa, group.saddr, ifindex); 224 225 if (ret < 0) 226 zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP"); 227 228 return ret; 229} 230 231/* multicast packet recieve socket */ 232int 233irdp_multicast_socket (int sock, struct in_addr group) 234{ 235 struct interface *ifp; 236 listnode node; 237 struct in_addr addr; 238 239 for (node = listhead (iflist); node; nextnode (node)) 240 { 241 ifp = getdata (node); 242 243 if ((ifp->flags & IFF_UP) && (ifp->flags & IFF_MULTICAST)) 244 { 245 ipv4_multicast_join (sock, group, addr, ifp->ifindex); 246 } 247 } 248 return 0; 249} 250 251struct 252{ 253 u_char type; 254 u_char code; 255 u_int16_t checksum; 256 u_char number; 257 u_char entry; 258 u_int16_t lifetime; 259} radv; 260 261void 262irdp_set (int sock) 263{ 264 struct in_addr irdp_group; 265 266 switch (irdp_mode) 267 { 268 case IRDP_HOST: 269 irdp_group.s_addr = htonl (INADDR_ALLHOSTS_GROUP); 270 break; 271 case IRDP_ROUTER: 272 irdp_group.s_addr = htonl (INADDR_ALLRTRS_GROUP); 273 break; 274 case IRDP_NONE: 275 default: 276 return; 277 } 278 irdp_multicast_socket (sock, irdp_group); 279} 280 281/* Make ICMP Router Solicitation Message. */ 282int 283make_solicit_packet (struct stream *s) 284{ 285 int size; 286 int checksum; 287 288 stream_putc (s, ICMP_ROUTERSOLICIT); /* Type. */ 289 stream_putc (s, 0); /* Code. */ 290 stream_putw (s, 0); /* Checksum. */ 291 stream_putl (s, 0); /* Reserved. */ 292 293 /* in_cksum return network byte order value */ 294 size = IRDP_SOLICIT_PACKET_SIZE; 295 checksum = in_cksum (s->data, size); 296 stream_putw_at (s, checksum, 2); 297 298 return IRDP_SOLICIT_PACKET_SIZE; 299} 300 301void 302irdp_solicit (int sock) 303{ 304 struct stream *s; 305 306 s = stream_new (IRDP_SOLICIT_PACKET_SIZE); 307 make_solicit_packet (s); 308 irdp_send_solicit (sock, s, IRDP_SOLICIT_PACKET_SIZE); 309} 310 311#define ICMP_MINLEN 8 312 313/* check validity of the packet */ 314int 315irdp_valid_check (char *packet, size_t size, struct sockaddr_in *from) 316{ 317 struct icmp *icmp; 318 319 icmp = (struct icmp *) packet; 320 321 if (in_cksum (packet, size)) { 322 zlog_warn ("ICMP %s packet from %s: Bad checksum, silently ignored", 323 icmp_type (icmp->icmp_type), 324 inet_ntoa (from->sin_addr)); 325 return -1; 326 } 327 328 if (icmp->icmp_code != 0) { 329 zlog_warn ("ICMP %s packet from %s: Bad ICMP type code, silently ignored", 330 icmp_type (icmp->icmp_type), 331 inet_ntoa (from->sin_addr)); 332 return -1; 333 } 334 335 if (size < ICMP_MINLEN) { 336 zlog_warn ("ICMP %s packet from %s: IMCP message length is short", 337 icmp_type (icmp->icmp_type), 338 inet_ntoa (from->sin_addr)); 339 return -1; 340 } 341 return 0; 342} 343 344int 345irdp_solicit_recv (struct stream *s, int size, struct sockaddr_in *from) 346{ 347 if (irdp_valid_check (s->data, size, from)) { 348 return 1; 349 } 350 return 0; 351} 352 353void 354irdp_advert_recv (struct stream *s, int size, struct sockaddr_in *from) 355{ 356 int i; 357 struct in_addr addr; 358 long pref; 359 360 if (irdp_valid_check (s->data, size, from) < 0) { 361 return; 362 } 363 364 radv.type = stream_getc (s); 365 radv.code = stream_getc (s); 366 radv.checksum = stream_getw (s); 367 radv.number = stream_getc (s); 368 radv.entry = stream_getc (s); 369 radv.lifetime = stream_getw (s); 370 371 printf ("type : %s\n", icmp_type (radv.type)); 372 printf ("number: %d\n", radv.number); 373 printf ("entry: %d\n", radv.entry); 374 printf ("lifetime: %d\n", radv.entry); 375 376 for (i = 0; i < radv.number; i++) 377 { 378 addr.s_addr = stream_getl (s); 379 pref = stream_getl (s); 380 route_add (addr, ntohl (pref)); 381 } 382 /* Packet size check is needed at here. */ 383} 384 385void 386irdp_packet_process (char *buf, int size, struct sockaddr_in *from) 387{ 388 struct ip *ip; 389 struct icmp *icmp; 390 int hlen; 391 struct stream *s = NULL; 392 393 ip = (struct ip *)buf; 394 hlen = ip->ip_hl << 2; 395 396 if (size < hlen + ICMP_MINLEN) 397 zlog_err ("ICMP relpy length is short\n"); 398 399 icmp = (struct icmp *)(buf + hlen); 400 401 stream_forward (s, hlen); 402 403 switch (icmp->icmp_type) 404 { 405 case ICMP_ROUTERADVERT: 406 irdp_advert_recv (s, size - hlen, from); 407 break; 408 case ICMP_ROUTERSOLICIT: 409 irdp_solicit_recv (s, size - hlen, from); 410 break; 411 } 412} 413 414/* Make socket for ICMP Router Discovery. */ 415int 416irdp_make_socket () 417{ 418 int sock; 419 struct protoent *pent; 420 421 if ((pent = getprotobyname ("icmp")) == NULL) { 422 perror ("getprotobyname"); 423 exit (1); 424 } 425 426 if ((sock = socket (AF_INET, SOCK_RAW, pent->p_proto)) < 0) 427 { 428 perror ("socket"); 429 exit (1); 430 } 431 432 return sock; 433} 434 435/* recv routine */ 436int 437irdp_recv (int sock) 438{ 439#define PACKET_BUF 4096 440 int nbytes; 441 struct sockaddr_in from; 442 int fromlen; 443 char buf[PACKET_BUF]; 444 445 fromlen = sizeof (from); 446 nbytes = recvfrom (sock, (char *)buf, PACKET_BUF, 0, 447 (struct sockaddr *)&from, &fromlen); 448 449 if (nbytes < 0) 450 { 451 perror ("recvfrom"); 452 exit (1); 453 } 454 455 irdp_packet_process (buf, nbytes, &from); 456 457 return 0; 458} 459 460/* irdp packet recv loop */ 461void 462irdp_loop (int sock) 463{ 464 while (1) 465 { 466 irdp_recv (sock); 467 } 468} 469 470DEFUN (ip_irdp, 471 ip_irdp_cmd, 472 "ip irdp", 473 IP_STR 474 "ICMP Router discovery on this interface\n") 475{ 476 return CMD_SUCCESS; 477} 478 479DEFUN (ip_irdp_multicast, 480 ip_irdp_multicast_cmd, 481 "ip irdp multicast", 482 IP_STR 483 "ICMP Router discovery on this interface\n" 484 "Send IRDP advertisement to the multicast address\n") 485{ 486 return CMD_SUCCESS; 487} 488 489DEFUN (ip_irdp_holdtime, 490 ip_irdp_holdtime_cmd, 491 "ip irdp holdtime <0-9000>", 492 IP_STR 493 "ICMP Router discovery on this interface\n" 494 "Set holdtime value\n" 495 "Holdtime value in seconds. Default is 1800 seconds\n") 496{ 497 return CMD_SUCCESS; 498} 499 500DEFUN (ip_irdp_maxadvertinterval, 501 ip_irdp_maxadvertinterval_cmd, 502 "ip irdp maxadvertinterval (0|<4-1800>)", 503 IP_STR 504 "ICMP Router discovery on this interface\n" 505 "Set maximum time between advertisement\n" 506 "Maximum advertisement interval in seconds\n") 507{ 508 return CMD_SUCCESS; 509} 510 511DEFUN (ip_irdp_minadvertinterval, 512 ip_irdp_minadvertinterval_cmd, 513 "ip irdp minadvertinterval <3-1800>", 514 IP_STR 515 "ICMP Router discovery on this interface\n" 516 "Set minimum time between advertisement\n" 517 "Minimum advertisement interval in seconds\n") 518{ 519 return CMD_SUCCESS; 520} 521 522DEFUN (ip_irdp_preference, 523 ip_irdp_preference_cmd, 524 /* "ip irdp preference <-2147483648-2147483647>", */ 525 "ip irdp preference <0-2147483647>", 526 IP_STR 527 "ICMP Router discovery on this interface\n" 528 "Set default preference level for this interface\n" 529 "Preference level\n") 530{ 531 return CMD_SUCCESS; 532} 533 534#if 0 535DEFUN (ip_irdp_address, 536 ip_irdp_address_cmd, 537 "ip irdp address A.B.C.D", 538 IP_STR 539 "ICMP Router discovery on this interface\n" 540 "Specify IRDP address and preference to proxy-advertise\n" 541 "Set IRDP address for proxy-advertise\n") 542{ 543 return CMD_SUCCESS; 544} 545#endif /* 0 */ 546 547DEFUN (ip_irdp_address_preference, 548 ip_irdp_address_preference_cmd, 549 "ip irdp address A.B.C.D <0-2147483647>", 550 IP_STR 551 "ICMP Router discovery on this interface\n" 552 "Specify IRDP address and preference to proxy-advertise\n" 553 "Set IRDP address for proxy-advertise\n" 554 "Preference level\n") 555{ 556 return CMD_SUCCESS; 557} 558 559void 560irdp_init () 561{ 562#ifdef FOX_CMD_SUPPORT 563 install_element (INTERFACE_NODE, &ip_irdp_cmd); 564 install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd); 565 install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd); 566 install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd); 567 install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd); 568 install_element (INTERFACE_NODE, &ip_irdp_preference_cmd); 569 install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd); 570#endif /* FOX_CMD_SUPPORT */ 571} 572