/** * IpToString * * Converts a sockaddr struct into a string. * * @param Address the address */ const char *IpToString(sockaddr *Address) { static char Buffer[256]; #ifdef _WIN32 DWORD BufferLength = sizeof(Buffer); if (WSAAddressToString(Address, SOCKADDR_LEN(Address->sa_family), NULL, Buffer, &BufferLength) != 0) { return NULL; } #else void *IpAddress; if (Address->sa_family == AF_INET) { IpAddress = &(((sockaddr_in *)Address)->sin_addr); } else { IpAddress = &(((sockaddr_in6 *)Address)->sin6_addr); } if (inet_ntop(Address->sa_family, IpAddress, Buffer, sizeof(Buffer)) == NULL) { return NULL; } #endif return Buffer; }
bool StringToIp(const char *IP, int Family, sockaddr *SockAddr, socklen_t Length) { memset(SockAddr, 0, Length); #ifdef _WIN32 socklen_t *LengthPtr = &Length; if (WSAStringToAddress(const_cast<char *>(IP), Family, NULL, SockAddr, LengthPtr) != 0) { return false; } #else if (Length < SOCKADDR_LEN(Family)) { return false; } if (inet_pton(Family, IP, SockAddr) <= 0) { return false; } #endif return true; }
/** * CreateListener * * Creates a new listening socket. * * @param Port the port this socket should listen on * @param BindIp the IP address this socket should be bound to * @param Family address family (i.e. IPv4 or IPv6) */ SOCKET CreateListener(unsigned int Port, const char *BindIp, int Family) { sockaddr *saddr; sockaddr_in sin; #ifdef HAVE_IPV6 sockaddr_in6 sin6; #endif /* HAVE_IPV6 */ const int optTrue = 1; bool Bound = false; SOCKET Listener; hostent *hent; Listener = socket(Family, SOCK_STREAM, IPPROTO_TCP); if (Listener == INVALID_SOCKET) { return INVALID_SOCKET; } #ifndef _WIN32 setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue)); #endif #ifdef HAVE_IPV6 if (Family == AF_INET) { #endif /* HAVE_IPV6 */ sin.sin_family = AF_INET; sin.sin_port = htons(Port); saddr = (sockaddr *)&sin; #ifdef HAVE_IPV6 /* HAVE_IPV6 */ } else if (Family == AF_INET6) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(Port); saddr = (sockaddr *)&sin6; #if !defined(_WIN32) && defined(IPV6_V6ONLY) setsockopt(Listener, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&optTrue, sizeof(optTrue)); #endif } else { closesocket(Listener); return INVALID_SOCKET; } #endif /* HAVE_IPV6 */ if (BindIp) { hent = gethostbyname(BindIp); if (hent) { #ifdef HAVE_IPV6 if (Family == AF_INET) { #endif /* HAVE_IPV6 */ sin.sin_addr.s_addr = ((in_addr*)hent->h_addr_list[0])->s_addr; #ifdef HAVE_IPV6 } else { memcpy(&(sin6.sin6_addr.s6_addr), &(((in6_addr*)hent->h_addr_list[0])->s6_addr), sizeof(in6_addr)); } #endif /* HAVE_IPV6 */ Bound = true; } } if (!Bound) { #ifdef HAVE_IPV6 if (Family == AF_INET) { #endif /* HAVE_IPV6 */ sin.sin_addr.s_addr = htonl(INADDR_ANY); #ifdef HAVE_IPV6 } else { const struct in6_addr v6any = IN6ADDR_ANY_INIT; memcpy(&(sin6.sin6_addr.s6_addr), &v6any, sizeof(in6_addr)); } #endif /* HAVE_IPV6 */ } if (bind(Listener, saddr, SOCKADDR_LEN(Family)) != 0) { closesocket(Listener); return INVALID_SOCKET; } if (listen(Listener, SOMAXCONN) != 0) { closesocket(Listener); return INVALID_SOCKET; } return Listener; }
/** * SocketAndConnect * * Creates a socket and connects to the specified host/port. You should use * SocketAndConnectResolved instead wherever possible as this function uses * blocking DNS requests. * * @param Host the host * @param Port the port * @param BindIp the ip address/hostname which should be used for binding the socket */ SOCKET SocketAndConnect(const char *Host, unsigned int Port, const char *BindIp) { unsigned long lTrue = 1; sockaddr_in sin, sloc; SOCKET Socket; hostent *hent; unsigned long addr; int code; if (Host == NULL || Port == 0) { return INVALID_SOCKET; } Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (Socket == INVALID_SOCKET) { return INVALID_SOCKET; } ioctlsocket(Socket, FIONBIO, &lTrue); if (BindIp && *BindIp) { sloc.sin_family = AF_INET; sloc.sin_port = 0; hent = gethostbyname(BindIp); if (hent) { in_addr *peer = (in_addr *)hent->h_addr_list[0]; sloc.sin_addr.s_addr = peer->s_addr; } else { addr = inet_addr(BindIp); sloc.sin_addr.s_addr = addr; } bind(Socket, (sockaddr *)&sloc, sizeof(sloc)); } sin.sin_family = AF_INET; sin.sin_port = htons(Port); hent = gethostbyname(Host); if (hent) { in_addr *peer = (in_addr *)hent->h_addr_list[0]; sin.sin_addr.s_addr = peer->s_addr; } else { addr = inet_addr(Host); sin.sin_addr.s_addr = addr; } code = connect(Socket, (const sockaddr *)&sin, sizeof(sin)); #ifdef _WIN32 if (code != 0 && errno != WSAEWOULDBLOCK) { #else if (code != 0 && errno != EINPROGRESS) { #endif closesocket(Socket); return INVALID_SOCKET; } return Socket; } /** * SocketAndConnectResolved * * Creates a socket and connects to the specified host/port. * * @param Host the host's ip address * @param BindIp the ip address which should be used for binding the socket */ SOCKET SocketAndConnectResolved(const sockaddr *Host, const sockaddr *BindIp) { unsigned long lTrue = 1; int Code, Size; SOCKET Socket = socket(Host->sa_family, SOCK_STREAM, IPPROTO_TCP); if (Socket == INVALID_SOCKET) { return INVALID_SOCKET; } ioctlsocket(Socket, FIONBIO, &lTrue); if (BindIp != NULL) { bind(Socket, (sockaddr *)BindIp, SOCKADDR_LEN(BindIp->sa_family)); } Size = SOCKADDR_LEN(Host->sa_family); Code = connect(Socket, Host, Size); #ifdef _WIN32 if (Code != 0 && WSAGetLastError() != WSAEWOULDBLOCK) { #else if (Code != 0 && errno != EINPROGRESS) { #endif closesocket(Socket); return INVALID_SOCKET; } return Socket; } /** * NickFromHostname * * Given a complete hostmask (nick!ident\@host) this function returns a copy * of the nickname. The result must be passed to free() when it is no longer used. * * @param Hostmask the hostmask */ char *NickFromHostmask(const char *Hostmask) { char *Copy; const char *ExclamationMark; ExclamationMark = strchr(Hostmask, '!'); if (ExclamationMark == NULL) { return NULL; } Copy = strdup(Hostmask); if (AllocFailed(Copy)) { return NULL; } Copy[ExclamationMark - Hostmask] = '\0'; return Copy; }
/* get local address against the destination. */ struct sockaddr * getlocaladdr(struct sockaddr *remote, struct sockaddr *hint, int lport) { struct sockaddr *local; socklen_t local_len = sizeof(struct sockaddr_storage); int s; /* for dummy connection */ extern struct rcf_interface *rcf_interface_head; if (hint && hint->sa_family == remote->sa_family) { local = rcs_sadup(hint); goto got; } /* allocate buffer */ if ((local = racoon_calloc(1, local_len)) == NULL) { plog(PLOG_INTERR, PLOGLOC, NULL, "failed to get address buffer.\n"); goto err; } /* get real interface received packet */ if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "socket (%s)\n", strerror(errno)); goto err; } if ((rcf_interface_head->application_bypass != RCT_BOOL_OFF) && (setsockopt_bypass(s, remote->sa_family) < 0)) { close(s); goto err; } if (connect(s, remote, SOCKADDR_LEN(remote)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "connect (%s)\n", strerror(errno)); close(s); goto err; } if (getsockname(s, local, &local_len) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "getsockname (%s)\n", strerror(errno)); close(s); goto err; } close(s); got: /* specify local port */ local->sa_family = remote->sa_family; switch (remote->sa_family) { case AF_INET: ((struct sockaddr_in *)local)->sin_port = htons(lport); break; #ifdef INET6 case AF_INET6: ((struct sockaddr_in6 *)local)->sin6_port = htons(lport); break; #endif default: plog(PLOG_INTERR, PLOGLOC, NULL, "getlocaladdr: unexpected address family (%d)\n", remote->sa_family); goto err; } return local; err: if (local != NULL) racoon_free(local); return NULL; }
/* send packet, with fixing src/dst address pair. */ int sendfromto(int s, const void *buf, size_t buflen, struct sockaddr *src, struct sockaddr *dst, int cnt) { struct sockaddr_storage ss; socklen_t sslen; int len = 0, i; extern struct rcf_interface *rcf_interface_head; if (cnt <= 0) { TRACE((PLOGLOC, "cnt: %d\n", cnt)); return 0; } if (src->sa_family != dst->sa_family) { plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n"); return -1; } memset(&ss, 0, sizeof(ss)); sslen = sizeof(ss); if (getsockname(s, (struct sockaddr *)&ss, &sslen) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "getsockname (%s)\n", strerror(errno)); return -1; } plog(PLOG_DEBUG, PLOGLOC, NULL, "sockname %s\n", rcs_sa2str((struct sockaddr *)&ss)); plog(PLOG_DEBUG, PLOGLOC, NULL, "send packet from %s\n", rcs_sa2str(src)); plog(PLOG_DEBUG, PLOGLOC, NULL, "send packet to %s\n", rcs_sa2str(dst)); if (src->sa_family != SOCKADDR_FAMILY(&ss)) { plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n"); return -1; } switch (src->sa_family) { #if defined(INET6) && defined(ADVAPI) && !defined(IPV6_INRIA_VERSION) case AF_INET6: { struct msghdr m; struct cmsghdr *cm; struct iovec iov[2]; unsigned char cmsgbuf[256]; struct in6_pktinfo *pi; int ifindex; struct sockaddr_in6 src6, dst6; memcpy(&src6, src, sizeof(src6)); memcpy(&dst6, dst, sizeof(dst6)); /* XXX take care of other cases, such as site-local */ ifindex = 0; if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr) || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) { ifindex = src6.sin6_scope_id; /*??? */ } /* XXX some sanity check on dst6.sin6_scope_id */ /* flowinfo for IKE? mmm, maybe useful but for now make it 0 */ src6.sin6_flowinfo = dst6.sin6_flowinfo = 0; memset(&m, 0, sizeof(m)); m.msg_name = (caddr_t)&dst6; m.msg_namelen = sizeof(dst6); iov[0].iov_base = (char *)buf; iov[0].iov_len = buflen; m.msg_iov = iov; m.msg_iovlen = 1; memset(cmsgbuf, 0, sizeof(cmsgbuf)); cm = (struct cmsghdr *)cmsgbuf; m.msg_control = (caddr_t)cm; m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_type = IPV6_PKTINFO; pi = (struct in6_pktinfo *)CMSG_DATA(cm); memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr)); pi->ipi6_ifindex = ifindex; plog(PLOG_DEBUG, PLOGLOC, NULL, "src6 %s %d\n", rcs_sa2str((struct sockaddr *)&src6), src6.sin6_scope_id); plog(PLOG_DEBUG, PLOGLOC, NULL, "dst6 %s %d\n", rcs_sa2str((struct sockaddr *)&dst6), dst6.sin6_scope_id); for (i = 0; i < cnt; i++) { len = sendmsg(s, &m, 0 /*MSG_DONTROUTE */ ); if (len < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "sendmsg (%s)\n", strerror(errno)); return -1; } plog(PLOG_DEBUG, PLOGLOC, NULL, "%d times of %d bytes message will be sent " "to %s\n", i + 1, len, rcs_sa2str(dst)); } plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen); return len; } #endif default: { int needclose = 0; int sendsock; if (rcs_cmpsa((struct sockaddr *)&ss, src) == 0) { sendsock = s; needclose = 0; } else { int yes = 1; /* * Use newly opened socket for sending packets. * NOTE: this is unsafe, because if the peer is quick enough * the packet from the peer may be queued into sendsock. * Better approach is to prepare bind'ed udp sockets for * each of the interface addresses. */ sendsock = socket(src->sa_family, SOCK_DGRAM, 0); if (sendsock < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "socket (%s)\n", strerror(errno)); return -1; } #ifdef SO_REUSEPORT if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEPORT, (void *)&yes, sizeof(yes)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "setsockopt (%s)\n", strerror(errno)); close(sendsock); return -1; } #else #ifdef SO_REUSEADDR if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "setsockopt (%s)\n", strerror(errno)); close(sendsock); return -1; } #else #error #endif #endif #ifdef IPV6_USE_MIN_MTU if (src->sa_family == AF_INET6 && setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (void *)&yes, sizeof(yes)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "setsockopt (%s)\n", strerror(errno)); close(sendsock); return -1; } #endif if (rcf_interface_head->application_bypass != RCT_BOOL_OFF && setsockopt_bypass(sendsock, src->sa_family) < 0) { close(sendsock); return -1; } if (bind (sendsock, (struct sockaddr *)src, SOCKADDR_LEN(src)) < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "bind 1 (%s)\n", strerror(errno)); close(sendsock); return -1; } needclose = 1; } for (i = 0; i < cnt; i++) { #ifdef DEBUG extern uint32_t debug_send; static int send_count = 0; if (debug_send & (1 << (send_count++ % 32))) { /* simulate a network packet drop */ TRACE((PLOGLOC, "debug_send %d drop\n", send_count)); len = buflen; } else #endif len = sendto(sendsock, buf, buflen, 0, dst, SOCKADDR_LEN(dst)); if (len < 0) { plog(PLOG_INTERR, PLOGLOC, NULL, "sendto (%s)\n", strerror(errno)); if (needclose) close(sendsock); return len; } plog(PLOG_DEBUG, PLOGLOC, NULL, "%d times of %d bytes message will be sent " "to %s\n", i + 1, len, rcs_sa2str(dst)); } plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen); if (needclose) close(sendsock); return len; } } }