irdp.c 12 KB

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