File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_sock.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (8 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    1: /*
    2:   PIM for Quagga
    3:   Copyright (C) 2008  Everton da Silva Marques
    4: 
    5:   This program is free software; you can redistribute it and/or modify
    6:   it under the terms of the GNU General Public License as published by
    7:   the Free Software Foundation; either version 2 of the License, or
    8:   (at your option) any later version.
    9: 
   10:   This program is distributed in the hope that it will be useful, but
   11:   WITHOUT ANY WARRANTY; without even the implied warranty of
   12:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:   General Public License for more details.
   14:   
   15:   You should have received a copy of the GNU General Public License
   16:   along with this program; see the file COPYING; if not, write to the
   17:   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   18:   MA 02110-1301 USA
   19:   
   20:   $QuaggaId: $Format:%an, %ai, %h$ $
   21: */
   22: 
   23: #include <zebra.h>
   24: #include "pim_mroute.h"
   25: 
   26: #include <sys/types.h>
   27: #include <sys/socket.h>
   28: #include <netinet/in.h>
   29: #include <netinet/igmp.h>
   30: #include <arpa/inet.h>
   31: #include <unistd.h>
   32: #include <netdb.h>
   33: #include <errno.h>
   34: 
   35: #include "log.h"
   36: #include "privs.h"
   37: 
   38: #include "pimd.h"
   39: #include "pim_sock.h"
   40: #include "pim_str.h"
   41: #include "pim_igmp_join.h"
   42: 
   43: /* GLOBAL VARS */
   44: extern struct zebra_privs_t pimd_privs;
   45: 
   46: int pim_socket_raw(int protocol)
   47: {
   48:   int fd;
   49: 
   50:   if ( pimd_privs.change (ZPRIVS_RAISE) )
   51:        zlog_err ("pim_sockek_raw: could not raise privs, %s",
   52:                  safe_strerror (errno) );
   53: 
   54:   fd = socket(AF_INET, SOCK_RAW, protocol);
   55: 
   56:   if ( pimd_privs.change (ZPRIVS_LOWER) )
   57:        zlog_err ("pim_socket_raw: could not lower privs, %s",
   58:                  safe_strerror (errno) );
   59: 
   60:   if (fd < 0) {
   61:     zlog_warn("Could not create raw socket: errno=%d: %s",
   62: 	      errno, safe_strerror(errno));
   63:     return PIM_SOCK_ERR_SOCKET;
   64:   }
   65:   
   66:   return fd;
   67: }
   68: 
   69: int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop)
   70: {
   71:   int fd;
   72: 
   73:   fd = pim_socket_raw(protocol);
   74:   if (fd < 0) {
   75:     zlog_warn("Could not create multicast socket: errno=%d: %s",
   76: 	      errno, safe_strerror(errno));
   77:     return PIM_SOCK_ERR_SOCKET;
   78:   }
   79: 
   80:   /* Needed to obtain destination address from recvmsg() */
   81:   {
   82: #if defined(HAVE_IP_PKTINFO)
   83:     /* Linux and Solaris IP_PKTINFO */
   84:     int opt = 1;
   85:     if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) {
   86:       zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
   87: 		fd, errno, safe_strerror(errno));
   88:     }
   89: #elif defined(HAVE_IP_RECVDSTADDR)
   90:     /* BSD IP_RECVDSTADDR */
   91:     int opt = 1;
   92:     if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) {
   93:       zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
   94: 		fd, errno, safe_strerror(errno));
   95:     }
   96: #else
   97:     zlog_err("%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
   98: 	     __FILE__, __PRETTY_FUNCTION__);
   99:     close(fd);
  100:     return PIM_SOCK_ERR_DSTADDR;
  101: #endif
  102:   }
  103: 
  104:   
  105:   /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. Message Formats)*/
  106:   if (protocol == IPPROTO_IGMP) {
  107:     char ra[4];
  108:     ra[0] = 148;
  109:     ra[1] = 4;
  110:     ra[2] = 0;
  111:     ra[3] = 0;
  112:     if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) {
  113:       zlog_warn("Could not set Router Alert Option on socket fd=%d: errno=%d: %s",
  114: 		fd, errno, safe_strerror(errno));
  115:       close(fd);
  116:       return PIM_SOCK_ERR_RA;
  117:     }
  118:   }
  119: 
  120:   {
  121:     int reuse = 1;
  122:     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
  123: 		   (void *) &reuse, sizeof(reuse))) {
  124:       zlog_warn("Could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
  125: 		fd, errno, safe_strerror(errno));
  126:       close(fd);
  127:       return PIM_SOCK_ERR_REUSE;
  128:     }
  129:   }
  130: 
  131:   {
  132:     const int MTTL = 1;
  133:     int ttl = MTTL;
  134:     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
  135: 		   (void *) &ttl, sizeof(ttl))) {
  136:       zlog_warn("Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s",
  137: 		MTTL, fd, errno, safe_strerror(errno));
  138:       close(fd);
  139:       return PIM_SOCK_ERR_TTL;
  140:     }
  141:   }
  142: 
  143:   if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
  144: 		 (void *) &loop, sizeof(loop))) {
  145:     zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s",
  146: 	      loop ? "enable" : "disable",
  147: 	      fd, errno, safe_strerror(errno));
  148:     close(fd);
  149:     return PIM_SOCK_ERR_LOOP;
  150:   }
  151: 
  152:   if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
  153: 		 (void *) &ifaddr, sizeof(ifaddr))) {
  154:     zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
  155: 	      fd, errno, safe_strerror(errno));
  156:     close(fd);
  157:     return PIM_SOCK_ERR_IFACE;
  158:   }
  159: 
  160:   {
  161:     long flags;
  162: 
  163:     flags = fcntl(fd, F_GETFL, 0);
  164:     if (flags < 0) {
  165:       zlog_warn("Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
  166: 		fd, errno, safe_strerror(errno));
  167:       close(fd);
  168:       return PIM_SOCK_ERR_NONBLOCK_GETFL;
  169:     }
  170: 
  171:     if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
  172:       zlog_warn("Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
  173: 		fd, errno, safe_strerror(errno));
  174:       close(fd);
  175:       return PIM_SOCK_ERR_NONBLOCK_SETFL;
  176:     }
  177:   }
  178: 
  179:   return fd;
  180: }
  181: 
  182: int pim_socket_join(int fd, struct in_addr group,
  183: 		    struct in_addr ifaddr, ifindex_t ifindex)
  184: {
  185:   int ret;
  186: 
  187: #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
  188:   struct ip_mreqn opt;
  189: #else
  190:   struct ip_mreq opt;
  191: #endif
  192: 
  193:   opt.imr_multiaddr = group;
  194: 
  195: #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
  196:   opt.imr_address   = ifaddr;
  197:   opt.imr_ifindex   = ifindex;
  198: #else
  199:   opt.imr_interface = ifaddr;
  200: #endif
  201: 
  202:   ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));
  203:   if (ret) {
  204:     char group_str[100];
  205:     char ifaddr_str[100];
  206:     if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
  207:       sprintf(group_str, "<group?>");
  208:     if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
  209:       sprintf(ifaddr_str, "<ifaddr?>");
  210: 
  211:     zlog_err("Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s",
  212: 	     fd, group_str, ifaddr_str, errno, safe_strerror(errno));
  213:     return ret;
  214:   }
  215: 
  216:   if (PIM_DEBUG_TRACE) {
  217:     char group_str[100];
  218:     char ifaddr_str[100];
  219:     if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
  220:       sprintf(group_str, "<group?>");
  221:     if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
  222:       sprintf(ifaddr_str, "<ifaddr?>");
  223: 
  224:     zlog_debug("Socket fd=%d joined group %s on interface address %s",
  225: 	       fd, group_str, ifaddr_str);
  226:   }
  227: 
  228:   return ret;
  229: }
  230: 
  231: int pim_socket_join_source(int fd, ifindex_t ifindex,
  232: 			   struct in_addr group_addr,
  233: 			   struct in_addr source_addr,
  234: 			   const char *ifname)
  235: {
  236:   if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) {
  237:     int e = errno;
  238:     char group_str[100];
  239:     char source_str[100];
  240:     pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
  241:     pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
  242:     zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
  243: 	      __PRETTY_FUNCTION__,
  244: 	      fd, group_str, source_str, ifindex, ifname,
  245: 	      e, safe_strerror(e));
  246:     return -1;
  247:   }
  248: 
  249:   return 0;
  250: }
  251: 
  252: int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
  253: 			  struct sockaddr_in *from, socklen_t *fromlen,
  254: 			  struct sockaddr_in *to, socklen_t *tolen,
  255: 			  ifindex_t *ifindex)
  256: {
  257:   struct msghdr msgh;
  258:   struct cmsghdr *cmsg;
  259:   struct iovec iov;
  260:   char cbuf[1000];
  261:   int err;
  262: 
  263:   /*
  264:    * IP_PKTINFO / IP_RECVDSTADDR don't yield sin_port.
  265:    * Use getsockname() to get sin_port.
  266:    */
  267:   if (to) {
  268:     struct sockaddr_in si;
  269:     socklen_t si_len = sizeof(si);
  270:     
  271:     ((struct sockaddr_in *) to)->sin_family = AF_INET;
  272: 
  273:     if (pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len)) {
  274:       ((struct sockaddr_in *) to)->sin_port        = ntohs(0);
  275:       ((struct sockaddr_in *) to)->sin_addr.s_addr = ntohl(0);
  276:     }
  277:     else {
  278:       ((struct sockaddr_in *) to)->sin_port = si.sin_port;
  279:       ((struct sockaddr_in *) to)->sin_addr = si.sin_addr;
  280:     }
  281: 
  282:     if (tolen) 
  283:       *tolen = sizeof(si);
  284:   }
  285: 
  286:   memset(&msgh, 0, sizeof(struct msghdr));
  287:   iov.iov_base = buf;
  288:   iov.iov_len  = len;
  289:   msgh.msg_control = cbuf;
  290:   msgh.msg_controllen = sizeof(cbuf);
  291:   msgh.msg_name = from;
  292:   msgh.msg_namelen = fromlen ? *fromlen : 0;
  293:   msgh.msg_iov  = &iov;
  294:   msgh.msg_iovlen = 1;
  295:   msgh.msg_flags = 0;
  296: 
  297:   err = recvmsg(fd, &msgh, 0);
  298:   if (err < 0)
  299:     return err;
  300: 
  301:   if (fromlen)
  302:     *fromlen = msgh.msg_namelen;
  303: 
  304:   for (cmsg = CMSG_FIRSTHDR(&msgh);
  305:        cmsg != NULL;
  306:        cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
  307: 
  308: #ifdef HAVE_IP_PKTINFO
  309:     if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
  310:       struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
  311:       if (to)
  312: 	((struct sockaddr_in *) to)->sin_addr = i->ipi_addr;
  313:       if (tolen)
  314: 	*tolen = sizeof(struct sockaddr_in);
  315:       if (ifindex)
  316: 	*ifindex = i->ipi_ifindex;
  317: 
  318:       if (to && PIM_DEBUG_PACKETS) {
  319: 	char to_str[100];
  320: 	pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
  321: 	zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d",
  322: 		   __PRETTY_FUNCTION__,
  323: 		   to_str, ntohs(to->sin_port));
  324:       }
  325: 
  326:       break;
  327:     }
  328: #endif
  329: 
  330: #ifdef HAVE_IP_RECVDSTADDR
  331:     if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
  332:       struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
  333:       if (to)
  334: 	((struct sockaddr_in *) to)->sin_addr = *i;
  335:       if (tolen)
  336: 	*tolen = sizeof(struct sockaddr_in);
  337: 
  338:       if (to && PIM_DEBUG_PACKETS) {
  339: 	char to_str[100];
  340: 	pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
  341: 	zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d",
  342: 		   __PRETTY_FUNCTION__,
  343: 		   to_str, ntohs(to->sin_port));
  344:       }
  345: 
  346:       break;
  347:     }
  348: #endif
  349: 
  350: #if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX)
  351:       if (cmsg->cmsg_type == IP_RECVIF)
  352: 	if (ifindex)
  353: 	  *ifindex = CMSG_IFINDEX(cmsg);
  354: #endif
  355: 
  356:   } /* for (cmsg) */
  357: 
  358:   return err; /* len */
  359: }
  360: 
  361: int pim_socket_mcastloop_get(int fd)
  362: {
  363:   int loop;
  364:   socklen_t loop_len = sizeof(loop);
  365:   
  366:   if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
  367: 		 &loop, &loop_len)) {
  368:     int e = errno;
  369:     zlog_warn("Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s",
  370: 	      fd, errno, safe_strerror(errno));
  371:     errno = e;
  372:     return PIM_SOCK_ERR_LOOP;
  373:   }
  374:   
  375:   return loop;
  376: }
  377: 
  378: int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen)
  379: {
  380:   if (getsockname(fd, name, namelen)) {
  381:     int e = errno;
  382:     zlog_warn("Could not get Socket Name for socket fd=%d: errno=%d: %s",
  383: 	      fd, errno, safe_strerror(errno));
  384:     errno = e;
  385:     return PIM_SOCK_ERR_NAME;
  386:   }
  387: 
  388:   return PIM_SOCK_ERR_NONE;
  389: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>