static int ssmpingd_socket(struct in_addr addr, int port, int mttl) { struct sockaddr_in sockaddr; int fd; fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { flog_err_sys(LIB_ERR_SOCKET, "%s: could not create socket: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; } sockaddr.sin_family = AF_INET; sockaddr.sin_addr = addr; sockaddr.sin_port = htons(port); if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); zlog_warn( "%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s", __PRETTY_FUNCTION__, fd, addr_str, port, sizeof(sockaddr), errno, safe_strerror(errno)); close(fd); return -1; } /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) /* Linux and Solaris IP_PKTINFO */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn( "%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #elif defined(HAVE_IP_RECVDSTADDR) /* BSD IP_RECVDSTADDR */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { zlog_warn( "%s: could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #else flog_err( LIB_ERR_DEVELOPMENT, "%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", __FILE__, __PRETTY_FUNCTION__); close(fd); return -1; #endif } { int reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(reuse))) { zlog_warn( "%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&mttl, sizeof(mttl))) { zlog_warn( "%s: could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, mttl, fd, errno, safe_strerror(errno)); close(fd); return -1; } if (setsockopt_ipv4_multicast_loop(fd, 0)) { zlog_warn( "%s: could not disable Multicast Loopback Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_LOOP; } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&addr, sizeof(addr))) { zlog_warn( "%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } { long flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { zlog_warn( "%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { zlog_warn( "%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } } return fd; }
void send_packet(struct interface *ifp, struct stream *s, u_int32_t dst, struct prefix *p, u_int32_t ttl) { static struct sockaddr_in sockdst = {AF_INET}; struct ip *ip; struct icmphdr *icmp; struct msghdr *msg; struct cmsghdr *cmsg; struct iovec iovector; char msgbuf[256]; char buf[256]; struct in_pktinfo *pktinfo; u_long src; if (!(ifp->flags & IFF_UP)) return; if (!p) src = ntohl(p->u.prefix4.s_addr); else src = 0; /* Is filled in */ ip = (struct ip *) buf; ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_v = IPVERSION; ip->ip_tos = IPTOS_PREC_INTERNETCONTROL; ip->ip_off = 0L; ip->ip_p = 1; /* IP_ICMP */ ip->ip_ttl = ttl; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; icmp = (struct icmphdr *) (buf + sizeof (struct ip)); /* Merge IP header with icmp packet */ assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip))); stream_get(icmp, s, stream_get_endp(s)); /* icmp->checksum is already calculated */ ip->ip_len = sizeof(struct ip) + stream_get_endp(s); setsockopt_ipv4_hdrincl (irdp_sock, 1); if (dst == INADDR_BROADCAST) setsockopt_so_broadcast (irdp_sock, 1); else setsockopt_ipv4_multicast_loop (irdp_sock, 0); memset(&sockdst,0,sizeof(sockdst)); sockdst.sin_family=AF_INET; sockdst.sin_addr.s_addr = dst; cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr)); cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg); pktinfo->ipi_ifindex = ifp->ifindex; pktinfo->ipi_spec_dst.s_addr = src; pktinfo->ipi_addr.s_addr = src; iovector.iov_base = (void *) buf; iovector.iov_len = ip->ip_len; msg = (struct msghdr *) msgbuf; msg->msg_name = &sockdst; msg->msg_namelen = sizeof(sockdst); msg->msg_iov = &iovector; msg->msg_iovlen = 1; msg->msg_control = cmsg; msg->msg_controllen = cmsg->cmsg_len; sockopt_iphdrincl_swab_htosys (ip); if (sendmsg(irdp_sock, msg, 0) < 0) { zlog_warn("sendto %s", safe_strerror (errno)); } /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */ }