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>