irdp_packet.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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 "sockunion.h"
  56. #include "log.h"
  57. /* GLOBAL VARS */
  58. int irdp_sock;
  59. char b1[16], b2[16], b3[16], b4[16]; /* For inet_2a */
  60. extern struct zebra_t zebrad;
  61. extern struct thread *t_irdp_raw;
  62. extern struct interface *get_iflist_ifp(int idx);
  63. int in_cksum (void *ptr, int nbytes);
  64. void process_solicit (struct interface *ifp);
  65. void parse_irdp_packet(char *p,
  66. int len,
  67. struct interface *ifp)
  68. {
  69. struct ip *ip = (struct ip *)p ;
  70. struct icmphdr *icmp;
  71. struct in_addr src;
  72. int ip_hlen, ip_len;
  73. struct zebra_if *zi;
  74. struct irdp_interface *irdp;
  75. zi = ifp->info;
  76. if(!zi) return;
  77. irdp = &zi->irdp;
  78. if(!irdp) return;
  79. ip_hlen = ip->ip_hl*4;
  80. ip_len = ntohs(ip->ip_len);
  81. len = len - ip_hlen;
  82. src = ip->ip_src;
  83. if(ip_len < ICMP_MINLEN) {
  84. zlog_err ("IRDP: RX ICMP packet too short from %s\n",
  85. inet_ntoa (src));
  86. return;
  87. }
  88. /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
  89. len of IP-header) 14+20 */
  90. if(ip_len > IRDP_RX_BUF-34) {
  91. zlog_err ("IRDP: RX ICMP packet too long from %s\n",
  92. inet_ntoa (src));
  93. return;
  94. }
  95. if (in_cksum (ip, ip_len)) {
  96. zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
  97. inet_ntoa (src));
  98. return;
  99. }
  100. icmp = (struct icmphdr *) (p+ip_hlen);
  101. /* Handle just only IRDP */
  102. if( icmp->type == ICMP_ROUTERADVERT);
  103. else if( icmp->type == ICMP_ROUTERSOLICIT);
  104. else return;
  105. if (icmp->code != 0) {
  106. zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code, silently ignored",
  107. icmp->type,
  108. inet_ntoa (src));
  109. return;
  110. }
  111. if(ip->ip_dst.s_addr == INADDR_BROADCAST &&
  112. irdp->flags & IF_BROADCAST);
  113. else if ( ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP &&
  114. ! (irdp->flags & IF_BROADCAST));
  115. else { /* ERROR */
  116. zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
  117. inet_ntoa (src),
  118. ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP?
  119. "multicast" : inet_ntoa(ip->ip_dst),
  120. ifp->name,
  121. irdp->flags & IF_BROADCAST?
  122. "broadcast" : "multicast");
  123. zlog_warn ("IRDP: Please correct settings\n");
  124. return;
  125. }
  126. switch (icmp->type)
  127. {
  128. case ICMP_ROUTERADVERT:
  129. break;
  130. case ICMP_ROUTERSOLICIT:
  131. if(irdp->flags & IF_DEBUG_MESSAGES)
  132. zlog_warn ("IRDP: RX Solicit on %s from %s\n",
  133. ifp->name,
  134. inet_ntoa (src));
  135. process_solicit(ifp);
  136. break;
  137. default:
  138. zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
  139. icmp->type,
  140. inet_ntoa (src));
  141. }
  142. }
  143. int irdp_recvmsg (int sock,
  144. u_char *buf,
  145. int size,
  146. int *ifindex)
  147. {
  148. struct msghdr msg;
  149. struct iovec iov;
  150. struct cmsghdr *ptr;
  151. char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )];
  152. int ret;
  153. msg.msg_name = (void *)0;
  154. msg.msg_namelen = 0;
  155. msg.msg_iov = &iov;
  156. msg.msg_iovlen = 1;
  157. msg.msg_control = (void *) adata;
  158. msg.msg_controllen = sizeof adata;
  159. iov.iov_base = buf;
  160. iov.iov_len = size;
  161. ret = recvmsg (sock, &msg, 0);
  162. if (ret < 0) {
  163. zlog_warn("IRDP: recvmsg: read error %s", strerror(errno));
  164. return ret;
  165. }
  166. if (msg.msg_flags & MSG_TRUNC) {
  167. zlog_warn("IRDP: recvmsg: truncated message");
  168. return ret;
  169. }
  170. if (msg.msg_flags & MSG_CTRUNC) {
  171. zlog_warn("IRDP: recvmsg: truncated control message");
  172. return ret;
  173. }
  174. ifindex = getsockopt_pktinfo_ifindex (AF_INET, &msg);
  175. return ret;
  176. }
  177. int irdp_read_raw(struct thread *r)
  178. {
  179. struct interface *ifp;
  180. struct zebra_if *zi;
  181. struct irdp_interface *irdp;
  182. char buf[IRDP_RX_BUF];
  183. int ret, ifindex;
  184. int irdp_sock = THREAD_FD (r);
  185. t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
  186. ret = irdp_recvmsg (irdp_sock, buf, IRDP_RX_BUF, &ifindex);
  187. if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
  188. ifp = get_iflist_ifp(ifindex);
  189. if(! ifp ) return ret;
  190. zi= ifp->info;
  191. if(! zi ) return ret;
  192. irdp = &zi->irdp;
  193. if(! irdp ) return ret;
  194. if(! (irdp->flags & IF_ACTIVE)) {
  195. if(irdp->flags & IF_DEBUG_MISC)
  196. zlog_warn("IRDP: RX ICMP for disabled interface %s\n",
  197. ifp->name);
  198. return 0;
  199. }
  200. if(irdp->flags & IF_DEBUG_PACKET) {
  201. int i;
  202. zlog_warn("IRDP: RX (idx %d) ", ifindex);
  203. for(i=0; i < ret; i++) zlog_warn( "IRDP: RX %x ", buf[i]&0xFF);
  204. }
  205. parse_irdp_packet(buf, ret, ifp);
  206. return ret;
  207. }
  208. void send_packet(struct interface *ifp,
  209. struct stream *s,
  210. u_int32_t dst,
  211. struct prefix *p,
  212. u_int32_t ttl)
  213. {
  214. static struct sockaddr_in sockdst = {AF_INET};
  215. struct ip *ip;
  216. struct icmphdr *icmp;
  217. struct msghdr *msg;
  218. struct cmsghdr *cmsg;
  219. struct iovec iovector;
  220. char msgbuf[256];
  221. char buf[256];
  222. struct in_pktinfo *pktinfo;
  223. u_long src;
  224. int on;
  225. if (! (ifp->flags & IFF_UP)) return;
  226. if(!p) src = ntohl(p->u.prefix4.s_addr);
  227. else src = 0; /* Is filled in */
  228. ip = (struct ip *) buf;
  229. ip->ip_hl = sizeof(struct ip) >> 2;
  230. ip->ip_v = IPVERSION;
  231. ip->ip_tos = 0xC0;
  232. ip->ip_off = 0L;
  233. ip->ip_p = 1; /* IP_ICMP */
  234. ip->ip_ttl = ttl;
  235. ip->ip_src.s_addr = src;
  236. ip->ip_dst.s_addr = dst;
  237. icmp = (struct icmphdr *) (buf + 20);
  238. /* Merge IP header with icmp packet */
  239. stream_get(icmp, s, s->putp);
  240. /* icmp->checksum is already calculated */
  241. ip->ip_len = sizeof(struct ip) + s->putp;
  242. stream_free(s);
  243. on = 1;
  244. if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
  245. (char *) &on, sizeof(on)) < 0)
  246. zlog_warn("sendto %s", strerror (errno));
  247. if(dst == INADDR_BROADCAST ) {
  248. on = 1;
  249. if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
  250. (char *) &on, sizeof(on)) < 0)
  251. zlog_warn("sendto %s", strerror (errno));
  252. }
  253. if(dst != INADDR_BROADCAST) {
  254. on = 0;
  255. if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP,
  256. (char *)&on,sizeof(on)) < 0)
  257. zlog_warn("sendto %s", strerror (errno));
  258. }
  259. bzero(&sockdst,sizeof(sockdst));
  260. sockdst.sin_family=AF_INET;
  261. sockdst.sin_addr.s_addr = dst;
  262. cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
  263. cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
  264. cmsg->cmsg_level = SOL_IP;
  265. cmsg->cmsg_type = IP_PKTINFO;
  266. pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
  267. pktinfo->ipi_ifindex = ifp->ifindex;
  268. pktinfo->ipi_spec_dst.s_addr = src;
  269. pktinfo->ipi_addr.s_addr = src;
  270. iovector.iov_base = (void *) buf;
  271. iovector.iov_len = ip->ip_len;
  272. msg = (struct msghdr *) msgbuf;
  273. msg->msg_name = &sockdst;
  274. msg->msg_namelen = sizeof(sockdst);
  275. msg->msg_iov = &iovector;
  276. msg->msg_iovlen = 1;
  277. msg->msg_control = cmsg;
  278. msg->msg_controllen = cmsg->cmsg_len;
  279. if (sendmsg(irdp_sock, msg, 0) < 0) {
  280. zlog_warn("sendto %s", strerror (errno));
  281. }
  282. /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
  283. }
  284. #endif /* HAVE_IRDP */