Annotation of embedaddon/quagga/pimd/pim_sock.c, revision 1.1

1.1     ! misho       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>