irdp_packet.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. *
  3. * Copyright (C) 2000 Robert Olsson.
  4. * Swedish University of Agricultural Sciences
  5. *
  6. * This file is part of GNU Zebra.
  7. *
  8. * GNU Zebra is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2, or (at your option) any
  11. * later version.
  12. *
  13. * GNU Zebra is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with GNU Zebra; see the file COPYING. If not, write to the Free
  20. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  21. * 02111-1307, USA.
  22. */
  23. /*
  24. * This work includes work with the following copywrite:
  25. *
  26. * Copyright (C) 1997, 2000 Kunihiro Ishiguro
  27. *
  28. */
  29. /*
  30. * Thanks to Jens Låås at Swedish University of Agricultural Sciences
  31. * for reviewing and tests.
  32. */
  33. #include <zebra.h>
  34. #ifdef HAVE_IRDP
  35. #include "if.h"
  36. #include "vty.h"
  37. #include "sockunion.h"
  38. #include "prefix.h"
  39. #include "command.h"
  40. #include "memory.h"
  41. #include "stream.h"
  42. #include "ioctl.h"
  43. #include "connected.h"
  44. #include "log.h"
  45. #include "zclient.h"
  46. #include "thread.h"
  47. #include "zebra/interface.h"
  48. #include "zebra/rtadv.h"
  49. #include "zebra/rib.h"
  50. #include "zebra/zserv.h"
  51. #include "zebra/redistribute.h"
  52. #include "zebra/irdp.h"
  53. #include <netinet/ip_icmp.h>
  54. #include "if.h"
  55. #include "checksum.h"
  56. #include "sockunion.h"
  57. #include "log.h"
  58. #include "sockopt.h"
  59. /* GLOBAL VARS */
  60. int irdp_sock = -1;
  61. extern struct zebra_t zebrad;
  62. extern struct thread *t_irdp_raw;
  63. static void
  64. parse_irdp_packet(char *p,
  65. int len,
  66. struct interface *ifp)
  67. {
  68. struct ip *ip = (struct ip *)p ;
  69. struct icmphdr *icmp;
  70. struct in_addr src;
  71. int ip_hlen, iplen, datalen;
  72. struct zebra_if *zi;
  73. struct irdp_interface *irdp;
  74. zi = ifp->info;
  75. if (!zi)
  76. return;
  77. irdp = &zi->irdp;
  78. if (!irdp)
  79. return;
  80. ip_hlen = ip->ip_hl << 2;
  81. sockopt_iphdrincl_swab_systoh (ip);
  82. iplen = ip->ip_len;
  83. datalen = len - ip_hlen;
  84. src = ip->ip_src;
  85. if (len != iplen)
  86. {
  87. zlog_err ("IRDP: RX length doesn't match IP length");
  88. return;
  89. }
  90. if (iplen < ICMP_MINLEN)
  91. {
  92. zlog_err ("IRDP: RX ICMP packet too short from %s\n",
  93. inet_ntoa (src));
  94. return;
  95. }
  96. /* XXX: RAW doesn't receive link-layer, surely? ??? */
  97. /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
  98. len of IP-header) 14+20 */
  99. if (iplen > IRDP_RX_BUF-34)
  100. {
  101. zlog_err ("IRDP: RX ICMP packet too long from %s\n",
  102. inet_ntoa (src));
  103. return;
  104. }
  105. icmp = (struct icmphdr *) (p+ip_hlen);
  106. /* check icmp checksum */
  107. if (in_cksum (icmp, datalen) != icmp->checksum)
  108. {
  109. zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
  110. inet_ntoa (src));
  111. return;
  112. }
  113. /* Handle just only IRDP */
  114. if (!(icmp->type == ICMP_ROUTERADVERT
  115. || icmp->type == ICMP_ROUTERSOLICIT))
  116. return;
  117. if (icmp->code != 0)
  118. {
  119. zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code,"
  120. " silently ignored",
  121. icmp->type, inet_ntoa (src));
  122. return;
  123. }
  124. if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST)
  125. && (irdp->flags & IF_BROADCAST))
  126. ||
  127. (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
  128. && !(irdp->flags & IF_BROADCAST)))
  129. {
  130. zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
  131. inet_ntoa (src),
  132. ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ?
  133. "multicast" : inet_ntoa (ip->ip_dst),
  134. ifp->name,
  135. irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
  136. zlog_warn ("IRDP: Please correct settings\n");
  137. return;
  138. }
  139. switch (icmp->type)
  140. {
  141. case ICMP_ROUTERADVERT:
  142. break;
  143. case ICMP_ROUTERSOLICIT:
  144. if(irdp->flags & IF_DEBUG_MESSAGES)
  145. zlog_debug ("IRDP: RX Solicit on %s from %s\n",
  146. ifp->name,
  147. inet_ntoa (src));
  148. process_solicit(ifp);
  149. break;
  150. default:
  151. zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
  152. icmp->type,
  153. inet_ntoa (src));
  154. }
  155. }
  156. static int
  157. irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex)
  158. {
  159. struct msghdr msg;
  160. struct iovec iov;
  161. char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )];
  162. int ret;
  163. msg.msg_name = (void *)0;
  164. msg.msg_namelen = 0;
  165. msg.msg_iov = &iov;
  166. msg.msg_iovlen = 1;
  167. msg.msg_control = (void *) adata;
  168. msg.msg_controllen = sizeof adata;
  169. iov.iov_base = buf;
  170. iov.iov_len = size;
  171. ret = recvmsg (sock, &msg, 0);
  172. if (ret < 0) {
  173. zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno));
  174. return ret;
  175. }
  176. if (msg.msg_flags & MSG_TRUNC) {
  177. zlog_warn("IRDP: recvmsg: truncated message");
  178. return ret;
  179. }
  180. if (msg.msg_flags & MSG_CTRUNC) {
  181. zlog_warn("IRDP: recvmsg: truncated control message");
  182. return ret;
  183. }
  184. *ifindex = getsockopt_ifindex (AF_INET, &msg);
  185. return ret;
  186. }
  187. int irdp_read_raw(struct thread *r)
  188. {
  189. struct interface *ifp;
  190. struct zebra_if *zi;
  191. struct irdp_interface *irdp;
  192. char buf[IRDP_RX_BUF];
  193. int ret, ifindex = 0;
  194. int irdp_sock = THREAD_FD (r);
  195. t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
  196. ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex);
  197. if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
  198. ifp = if_lookup_by_index(ifindex);
  199. if(! ifp ) return ret;
  200. zi= ifp->info;
  201. if(! zi ) return ret;
  202. irdp = &zi->irdp;
  203. if(! irdp ) return ret;
  204. if(! (irdp->flags & IF_ACTIVE)) {
  205. if(irdp->flags & IF_DEBUG_MISC)
  206. zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name);
  207. return 0;
  208. }
  209. if(irdp->flags & IF_DEBUG_PACKET) {
  210. int i;
  211. zlog_debug("IRDP: RX (idx %d) ", ifindex);
  212. for(i=0; i < ret; i++) zlog_debug( "IRDP: RX %x ", buf[i]&0xFF);
  213. }
  214. parse_irdp_packet(buf, ret, ifp);
  215. return ret;
  216. }
  217. void
  218. send_packet(struct interface *ifp,
  219. struct stream *s,
  220. u_int32_t dst,
  221. struct prefix *p,
  222. u_int32_t ttl)
  223. {
  224. static struct sockaddr_in sockdst = {AF_INET};
  225. struct ip *ip;
  226. struct icmphdr *icmp;
  227. struct msghdr *msg;
  228. struct cmsghdr *cmsg;
  229. struct iovec iovector;
  230. char msgbuf[256];
  231. char buf[256];
  232. struct in_pktinfo *pktinfo;
  233. u_long src;
  234. int on;
  235. if (!(ifp->flags & IFF_UP))
  236. return;
  237. if (p)
  238. src = ntohl(p->u.prefix4.s_addr);
  239. else
  240. src = 0; /* Is filled in */
  241. ip = (struct ip *) buf;
  242. ip->ip_hl = sizeof(struct ip) >> 2;
  243. ip->ip_v = IPVERSION;
  244. ip->ip_tos = 0xC0;
  245. ip->ip_off = 0L;
  246. ip->ip_p = 1; /* IP_ICMP */
  247. ip->ip_ttl = ttl;
  248. ip->ip_src.s_addr = src;
  249. ip->ip_dst.s_addr = dst;
  250. icmp = (struct icmphdr *) (buf + sizeof (struct ip));
  251. /* Merge IP header with icmp packet */
  252. assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip)));
  253. stream_get(icmp, s, stream_get_endp(s));
  254. /* icmp->checksum is already calculated */
  255. ip->ip_len = sizeof(struct ip) + stream_get_endp(s);
  256. on = 1;
  257. if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
  258. (char *) &on, sizeof(on)) < 0)
  259. zlog_warn("sendto %s", safe_strerror (errno));
  260. if(dst == INADDR_BROADCAST ) {
  261. on = 1;
  262. if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
  263. (char *) &on, sizeof(on)) < 0)
  264. zlog_warn("sendto %s", safe_strerror (errno));
  265. }
  266. if(dst != INADDR_BROADCAST) {
  267. on = 0;
  268. if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP,
  269. (char *)&on,sizeof(on)) < 0)
  270. zlog_warn("sendto %s", safe_strerror (errno));
  271. }
  272. memset(&sockdst,0,sizeof(sockdst));
  273. sockdst.sin_family=AF_INET;
  274. sockdst.sin_addr.s_addr = dst;
  275. cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
  276. cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
  277. cmsg->cmsg_level = SOL_IP;
  278. cmsg->cmsg_type = IP_PKTINFO;
  279. pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
  280. pktinfo->ipi_ifindex = ifp->ifindex;
  281. pktinfo->ipi_spec_dst.s_addr = src;
  282. pktinfo->ipi_addr.s_addr = src;
  283. iovector.iov_base = (void *) buf;
  284. iovector.iov_len = ip->ip_len;
  285. msg = (struct msghdr *) msgbuf;
  286. msg->msg_name = &sockdst;
  287. msg->msg_namelen = sizeof(sockdst);
  288. msg->msg_iov = &iovector;
  289. msg->msg_iovlen = 1;
  290. msg->msg_control = cmsg;
  291. msg->msg_controllen = cmsg->cmsg_len;
  292. sockopt_iphdrincl_swab_htosys (ip);
  293. if (sendmsg(irdp_sock, msg, 0) < 0) {
  294. zlog_warn("sendto %s", safe_strerror (errno));
  295. }
  296. /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
  297. }
  298. #endif /* HAVE_IRDP */