gboolean gdm_address_equal (GdmAddress *a, GdmAddress *b) { guint8 fam_a; guint8 fam_b; g_return_val_if_fail (a != NULL, FALSE); g_return_val_if_fail (a->ss != NULL, FALSE); g_return_val_if_fail (b != NULL, FALSE); g_return_val_if_fail (b->ss != NULL, FALSE); fam_a = a->ss->ss_family; fam_b = b->ss->ss_family; if (fam_a == AF_INET && fam_b == AF_INET) { return v4_v4_equal (SIN (a->ss), SIN (b->ss)); } #ifdef ENABLE_IPV6 else if (fam_a == AF_INET6 && fam_b == AF_INET6) { return v6_v6_equal (SIN6 (a->ss), SIN6 (b->ss)); } #endif return FALSE; }
int get_user6( in_port_t lport, in_port_t fport, struct sockaddr_storage *laddr, struct sockaddr_storage *faddr) { struct socket *sockp, sock; struct inpcbhead pcb6; int ret; ret = getbuf(kinfo->nl[N_TCB6].n_value, &pcb6, sizeof(pcb6)); if (ret == -1) return (-1); sockp = getlist6(&pcb6, lport, fport, &SIN6(laddr)->sin6_addr, &SIN6(faddr)->sin6_addr); if (sockp == NULL) return (-1); ret = getbuf((u_long) sockp, &sock, sizeof(sock)); if (ret == -1) return (-1); return (sock.so_uid); }
int get_user6( in_port_t lport, in_port_t fport, struct sockaddr_storage *laddr, struct sockaddr_storage *faddr) { #if __NetBSD_Version__ >= 106250000 /* 1.6Y */ struct socket *sockp, sock; struct inpcbtable tcbtable; int ret; #ifdef SO_UIDINFO struct uidinfo uidinfo; #endif ret = getbuf(kinfo->nl[N_TCB6].n_value, &tcbtable, sizeof(tcbtable)); if (ret == -1) return (-1); sockp = getlist6(&tcbtable, (struct inpcbtable *) kinfo->nl[N_TCB6].n_value, lport, fport, &SIN6(laddr)->sin6_addr, &SIN6(faddr)->sin6_addr); #else struct socket *sockp, sock; struct in6pcb tcb6; int ret; ret = getbuf(kinfo->nl[N_TCB6].n_value, &tcb6, sizeof(tcb6)); if (ret == -1) return (-1); sockp = getlist6(&tcb6, lport, fport, &SIN6(laddr)->sin6_addr, &SIN6(faddr)->sin6_addr); #endif if (sockp == NULL) return (-1); if (getbuf((u_long) sockp, &sock, sizeof(sock)) == -1) return (-1); #ifdef SO_UIDINFO if (sock.so_uidinfo == NULL) return (-1); if (getbuf((u_long) sock.so_uidinfo, &uidinfo, sizeof(uidinfo)) == -1) return (-1); return (uidinfo.ui_uid); #else return (sock.so_uid); #endif }
/** * gnome_vfs_address_get_sockaddr: * @address: A #GnomeVFSAddress * @port: A valid port in host byte order to set in the returned sockaddr * structure. * @len: A pointer to an int which will contain the length of the * return sockaddr structure. * * This function tanslates @address into a equivalent * sockaddr structure. The port specified at @port will * be set in the structure and @len will be set to the length * of the structure. * * * Return value: A newly allocated sockaddr structure the caller must free * or %NULL if @address did not point to a valid #GnomeVFSAddress. **/ struct sockaddr * gnome_vfs_address_get_sockaddr (GnomeVFSAddress *address, guint16 port, int *len) { struct sockaddr *sa; g_return_val_if_fail (address != NULL, NULL); sa = g_memdup (address->sa, SA_SIZE (address->sa)); switch (address->sa->sa_family) { #ifdef ENABLE_IPV6 case AF_INET6: SIN6 (sa)->sin6_port = g_htons (port); if (len != NULL) { *len = SIN6_LEN; } break; #endif case AF_INET: SIN (sa)->sin_port = g_htons (port); if (len != NULL) { *len = SIN_LEN; } break; } return sa; }
/* * Converts the internet address plus port string in 'St' * into their network byte order representations. * * returns: - 0 -> conversion failed * - 1 -> only address part returned (inaddrPt) * - 2 -> address and port returned * */ static void getSockAdr(struct sockaddr *SaPt, socklen_t * SaLenPt, char *AddrSt, char *PortSt) { struct sockaddr_in *Sin4; struct sockaddr_in6 *Sin6; if (strchr(AddrSt, ':') == NULL) { Sin4 = SIN4(SaPt); memset(Sin4, 0, sizeof(*Sin4)); Sin4->sin_family = AF_INET; Sin4->sin_port = htons(atoi(PortSt)); if (inet_pton(AF_INET, AddrSt, &Sin4->sin_addr) <= 0) { smclog(LOG_ERR, "inet_pton failed for address %s: %m", AddrSt); exit(255); } *SaLenPt = sizeof(struct sockaddr_in); } else { Sin6 = SIN6(SaPt); memset(Sin6, 0, sizeof(*Sin6)); Sin6->sin6_family = AF_INET6; Sin6->sin6_port = htons(atoi(PortSt)); if (inet_pton(AF_INET6, AddrSt, &Sin6->sin6_addr) <= 0) { smclog(LOG_ERR, "inet_pton failed for address %s: %m", AddrSt); exit(255); } *SaLenPt = sizeof(struct sockaddr_in6); } }
struct in6_addr * get_addr(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); return (&SIN6(rti_info[RTAX_DST])->sin6_addr); }
int get_prefixlen(char *buf) { struct rt_msghdr *rtm = (struct rt_msghdr *)buf; struct sockaddr *sa, *rti_info[RTAX_MAX]; char *p, *lim; sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); sa = rti_info[RTAX_NETMASK]; p = (char *)(&SIN6(sa)->sin6_addr); lim = (char *)sa + sa->sa_len; return prefixlen(p, lim); }
/** * gnome_vfs_address_equal: * @a: A #GnomeVFSAddress * @b: A #GnomeVFSAddress to compare with @a * * Compares two #GnomeVFSAddress objects and returns TRUE if they have the * addresses are equal as well as the address family type. * * Return value: TRUE if the two addresses match. * * Since: 2.14 **/ gboolean gnome_vfs_address_equal (const GnomeVFSAddress *a, const GnomeVFSAddress *b) { guint8 fam_a; guint8 fam_b; g_return_val_if_fail (a != NULL || a->sa != NULL, FALSE); g_return_val_if_fail (b != NULL || b->sa != NULL, FALSE); fam_a = a->sa->sa_family; fam_b = b->sa->sa_family; if (fam_a == AF_INET && fam_b == AF_INET) { return v4_v4_equal (SIN (a->sa), SIN (b->sa)); } #ifdef ENABLE_IPV6 else if (fam_a == AF_INET6 && fam_b == AF_INET6) { return v6_v6_equal (SIN6 (a->sa), SIN6 (b->sa)); } #endif return FALSE; }
/** * gnome_vfs_address_to_string: * @address: A pointer to a #GnomeVFSAddress * * Translate @address to a printable string. * * Returns: A newly alloced string representation of @address which * the caller must free. * * Since: 2.8 **/ char * gnome_vfs_address_to_string (GnomeVFSAddress *address) { #ifdef G_OS_WIN32 char text_addr[100]; DWORD text_length = sizeof (text_addr); if (WSAAddressToString (address->sa, SA_SIZE (address->sa), NULL, text_addr, &text_length) == 0) return g_strdup (text_addr); return NULL; #else const char *text_addr; #ifdef HAVE_INET_NTOP char buf[MAX_ADDRSTRLEN]; #endif g_return_val_if_fail (address != NULL, NULL); text_addr = NULL; switch (address->sa->sa_family) { #if defined (ENABLE_IPV6) && defined (HAVE_INET_NTOP) case AF_INET6: text_addr = inet_ntop (AF_INET6, &SIN6 (address->sa)->sin6_addr, buf, sizeof (buf)); break; #endif case AF_INET: #if HAVE_INET_NTOP text_addr = inet_ntop (AF_INET, &SIN (address->sa)->sin_addr, buf, sizeof (buf)); #else text_addr = inet_ntoa (SIN (address->sa)->sin_addr); #endif /* HAVE_INET_NTOP */ break; } return text_addr != NULL ? g_strdup (text_addr) : NULL; #endif }
/** * gnome_vfs_address_match: * @a: A #GnomeVFSAddress * @b: A #GnomeVFSAddress to compare with @a * @prefix: Number of bits to take into account starting * from the left most one. * * Matches the first @prefix number of bits of two given #GnomeVFSAddress * objects and returns TRUE of they match otherwise FALSE. This function can * also match mapped address (i.e. IPv4 mapped IPv6 addresses). * * Return value: TRUE if the two addresses match. * * Since: 2.14 **/ gboolean gnome_vfs_address_match (const GnomeVFSAddress *a, const GnomeVFSAddress *b, guint prefix) { guint8 fam_a; guint8 fam_b; g_return_val_if_fail (a != NULL || a->sa != NULL, FALSE); g_return_val_if_fail (b != NULL || b->sa != NULL, FALSE); fam_a = a->sa->sa_family; fam_b = b->sa->sa_family; if (fam_a == AF_INET && fam_b == AF_INET) { if (prefix == 0 || prefix > 31) { return v4_v4_equal (SIN (a->sa), SIN (b->sa)); } else { return v4_v4_match (SIN (a->sa), SIN (b->sa), prefix); } } #ifdef ENABLE_IPV6 else if (fam_a == AF_INET6 && fam_b == AF_INET6) { if (prefix == 0 || prefix > 127) { return v6_v6_equal (SIN6 (a->sa), SIN6 (b->sa)); } else { return v6_v6_match (SIN6 (a->sa), SIN6 (b->sa), prefix); } } else if (fam_a == AF_INET && fam_b == AF_INET6) { return v4_v6_match (SIN (a->sa), SIN6 (b->sa), prefix); } else if (fam_a == AF_INET6 && fam_b == AF_INET) { return v4_v6_match (SIN (b->sa), SIN6 (a->sa), prefix); } #endif /* This is the case when we are trying to compare unkown family types */ g_assert_not_reached (); return FALSE; }
int sock_listen(struct sockaddr_storage *ss, in_port_t listen_port) { int sock; struct addrinfo *cur; const int one = 1; if (ss == NULL) return (-1); cur = xcalloc(1, sizeof(*cur)); cur->ai_family = ss->ss_family; switch (cur->ai_family) { case AF_INET6: cur->ai_addrlen = sizeof(struct sockaddr_in6); break; case AF_INET: cur->ai_addrlen = sizeof(struct sockaddr_in); break; default: debug("unknown family: %d", cur->ai_family); free(cur); return (-1); } cur->ai_addr = xmalloc(cur->ai_addrlen); memcpy(cur->ai_addr, ss, cur->ai_addrlen); if (cur->ai_family == AF_INET) SIN4(cur->ai_addr)->sin_port = htons(listen_port); else SIN6(cur->ai_addr)->sin6_port = htons(listen_port); sock = socket(cur->ai_family, SOCK_STREAM, 0); if (sock == -1) { debug("socket: %s", strerror(errno)); goto done; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) { debug("setsockopt: %s", strerror(errno)); close(sock); sock = -1; goto done; } if (bind(sock, cur->ai_addr, cur->ai_addrlen) != 0) { debug("bind: %s", strerror(errno)); close(sock); sock = -1; goto done; } if (listen(sock, SOMAXCONN) != 0) { debug("listen: %s", strerror(errno)); close(sock); sock = -1; goto done; } #ifndef WIN32 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { debug("fcntl: %s", strerror(errno)); close(sock); sock = -1; } #endif done: free(cur->ai_addr); free(cur); return (sock); }
char * get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) { struct rt_msghdr *rtm; struct ifa_msghdr *ifam; struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; *lenp = 0; for (rtm = (struct rt_msghdr *)buf; rtm < (struct rt_msghdr *)lim; rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { /* just for safety */ if (!rtm->rtm_msglen) { syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " "(buf=%p lim=%p rtm=%p)", __func__, buf, lim, rtm); break; } if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) { syslog(LOG_WARNING, "<%s> routing message version mismatch " "(buf=%p lim=%p rtm=%p)", __func__, buf, lim, rtm); continue; } if (FILTER_MATCH(rtm->rtm_type, filter) == 0) continue; switch (rtm->rtm_type) { case RTM_GET: case RTM_ADD: case RTM_DELETE: /* address related checks */ sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((dst = rti_info[RTAX_DST]) == NULL || dst->sa_family != AF_INET6) continue; if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) continue; if ((gw = rti_info[RTAX_GATEWAY]) == NULL || gw->sa_family != AF_LINK) continue; if (ifindex && SDL(gw)->sdl_index != ifindex) continue; if (rti_info[RTAX_NETMASK] == NULL) continue; /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_NEWADDR: case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; /* address related checks */ sa = (struct sockaddr *)(ifam + 1); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); if ((ifa = rti_info[RTAX_IFA]) == NULL || (ifa->sa_family != AF_INET && ifa->sa_family != AF_INET6)) continue; if (ifa->sa_family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) continue; if (ifindex && ifam->ifam_index != ifindex) continue; /* found */ *lenp = ifam->ifam_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_IFINFO: case RTM_IFANNOUNCE: /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ } } return ((char *)rtm); }
sin->sin_family = AF_INET; if (inet_aton(s, &sin->sin_addr)) ; else if ((hp = gethostbyname(s)) != NULL) bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length); else if ((np = getnetbyname(s)) != NULL) sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); else errx(1, "%s: bad value", s); } #ifdef INET6 #define SIN6(x) ((struct sockaddr_in6 *) &(x)) struct sockaddr_in6 *sin6tab[] = { SIN6(in6_addreq.ifra_addr), SIN6(in6_addreq.ifra_dstaddr)}; void in6_getaddr(char *s, int which) { struct sockaddr_in6 *sin = sin6tab[which]; sin->sin6_len = sizeof(*sin); sin->sin6_family = AF_INET6; if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) errx(1, "%s: bad value", s); } void in6_getprefix(char *plen, int which)
/* compares a host to an allowed sender list entry. Handles all subleties * including IPv4/v6 as well as domain name wildcards. * This is a helper to isAllowedSender. * Returns 0 if they do not match, 1 if they match and 2 if a DNS name would have been required. * contributed 2007-07-16 by [email protected] */ static int MaskCmp(struct NetAddr *pAllow, uint8_t bits, struct sockaddr *pFrom, const char *pszFromHost, int bChkDNS) { assert(pAllow != NULL); assert(pFrom != NULL); if(F_ISSET(pAllow->flags, ADDR_NAME)) { if(bChkDNS == 0) return 2; dbgprintf("MaskCmp: host=\"%s\"; pattern=\"%s\"\n", pszFromHost, pAllow->addr.HostWildcard); # if !defined(FNM_CASEFOLD) /* TODO: I don't know if that then works, seen on HP UX, what I have not in lab... ;) */ return(fnmatch(pAllow->addr.HostWildcard, pszFromHost, FNM_NOESCAPE) == 0); # else return(fnmatch(pAllow->addr.HostWildcard, pszFromHost, FNM_NOESCAPE|FNM_CASEFOLD) == 0); # endif } else {/* We need to compare an IP address */ switch (pFrom->sa_family) { case AF_INET: if (AF_INET == pAllow->addr.NetAddr->sa_family) return(( SIN(pFrom)->sin_addr.s_addr & htonl(0xffffffff << (32 - bits)) ) == SIN(pAllow->addr.NetAddr)->sin_addr.s_addr); else return 0; break; case AF_INET6: switch (pAllow->addr.NetAddr->sa_family) { case AF_INET6: { struct in6_addr ip, net; register uint8_t i; memcpy (&ip, &(SIN6(pFrom))->sin6_addr, sizeof (struct in6_addr)); memcpy (&net, &(SIN6(pAllow->addr.NetAddr))->sin6_addr, sizeof (struct in6_addr)); i = bits/32; if (bits % 32) ip.s6_addr32[i++] &= htonl(0xffffffff << (32 - (bits % 32))); for (; i < (sizeof ip.s6_addr32)/4; i++) ip.s6_addr32[i] = 0; return (memcmp (ip.s6_addr, net.s6_addr, sizeof ip.s6_addr) == 0 && (SIN6(pAllow->addr.NetAddr)->sin6_scope_id != 0 ? SIN6(pFrom)->sin6_scope_id == SIN6(pAllow->addr.NetAddr)->sin6_scope_id : 1)); } case AF_INET: { struct in6_addr *ip6 = &(SIN6(pFrom))->sin6_addr; struct in_addr *net = &(SIN(pAllow->addr.NetAddr))->sin_addr; if ((ip6->s6_addr32[3] & (u_int32_t) htonl((0xffffffff << (32 - bits)))) == net->s_addr && #if BYTE_ORDER == LITTLE_ENDIAN (ip6->s6_addr32[2] == (u_int32_t)0xffff0000) && #else (ip6->s6_addr32[2] == (u_int32_t)0x0000ffff) && #endif (ip6->s6_addr32[1] == 0) && (ip6->s6_addr32[0] == 0)) return 1; else return 0; } default: /* Unsupported AF */ return 0; } default: /* Unsupported AF */ return 0; } } }
/* function to add an allowed sender to the allowed sender list. The * root of the list is caller-provided, so it can be used for all * supported lists. The caller must provide a pointer to the root, * as it eventually needs to be updated. Also, a pointer to the * pointer to the last element must be provided (to speed up adding * list elements). * rgerhards, 2005-09-26 * If a hostname is given there are possible multiple entries * added (all addresses from that host). */ static rsRetVal AddAllowedSender(struct AllowedSenders **ppRoot, struct AllowedSenders **ppLast, struct NetAddr *iAllow, uint8_t iSignificantBits) { DEFiRet; assert(ppRoot != NULL); assert(ppLast != NULL); assert(iAllow != NULL); if (!F_ISSET(iAllow->flags, ADDR_NAME)) { if(iSignificantBits == 0) /* we handle this seperatly just to provide a better * error message. */ errmsg.LogError(0, NO_ERRCODE, "You can not specify 0 bits of the netmask, this would " "match ALL systems. If you really intend to do that, " "remove all $AllowedSender directives."); switch (iAllow->addr.NetAddr->sa_family) { case AF_INET: if((iSignificantBits < 1) || (iSignificantBits > 32)) { errmsg.LogError(0, NO_ERRCODE, "Invalid number of bits (%d) in IPv4 address - adjusted to 32", (int)iSignificantBits); iSignificantBits = 32; } MaskIP4 (&(SIN(iAllow->addr.NetAddr)->sin_addr), iSignificantBits); break; case AF_INET6: if((iSignificantBits < 1) || (iSignificantBits > 128)) { errmsg.LogError(0, NO_ERRCODE, "Invalid number of bits (%d) in IPv6 address - adjusted to 128", iSignificantBits); iSignificantBits = 128; } MaskIP6 (&(SIN6(iAllow->addr.NetAddr)->sin6_addr), iSignificantBits); break; default: /* rgerhards, 2007-07-16: We have an internal program error in this * case. However, there is not much we can do against it right now. Of * course, we could abort, but that would probably cause more harm * than good. So we continue to run. We simply do not add this line - the * worst thing that happens is that one host will not be allowed to * log. */ errmsg.LogError(0, NO_ERRCODE, "Internal error caused AllowedSender to be ignored, AF = %d", iAllow->addr.NetAddr->sa_family); ABORT_FINALIZE(RS_RET_ERR); } /* OK, entry constructed, now lets add it to the ACL list */ iRet = AddAllowedSenderEntry(ppRoot, ppLast, iAllow, iSignificantBits); } else { /* we need to process a hostname ACL */ if(glbl.GetDisableDNS()) { errmsg.LogError(0, NO_ERRCODE, "Ignoring hostname based ACLs because DNS is disabled."); ABORT_FINALIZE(RS_RET_OK); } if (!strchr (iAllow->addr.HostWildcard, '*') && !strchr (iAllow->addr.HostWildcard, '?') && ACLDontResolve == 0) { /* single host - in this case, we pull its IP addresses from DNS * and add IP-based ACLs. */ struct addrinfo hints, *res, *restmp; struct NetAddr allowIP; memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; # ifdef AI_ADDRCONFIG /* seems not to be present on all systems */ hints.ai_flags = AI_ADDRCONFIG; # endif if (getaddrinfo (iAllow->addr.HostWildcard, NULL, &hints, &res) != 0) { errmsg.LogError(0, NO_ERRCODE, "DNS error: Can't resolve \"%s\"", iAllow->addr.HostWildcard); if (ACLAddHostnameOnFail) { errmsg.LogError(0, NO_ERRCODE, "Adding hostname \"%s\" to ACL as a wildcard entry.", iAllow->addr.HostWildcard); iRet = AddAllowedSenderEntry(ppRoot, ppLast, iAllow, iSignificantBits); FINALIZE; } else { errmsg.LogError(0, NO_ERRCODE, "Hostname \"%s\" WON\'T be added to ACL.", iAllow->addr.HostWildcard); ABORT_FINALIZE(RS_RET_NOENTRY); } } for (restmp = res ; res != NULL ; res = res->ai_next) { switch (res->ai_family) { case AF_INET: /* add IPv4 */ iSignificantBits = 32; allowIP.flags = 0; if((allowIP.addr.NetAddr = MALLOC(res->ai_addrlen)) == NULL) { ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); } memcpy(allowIP.addr.NetAddr, res->ai_addr, res->ai_addrlen); if((iRet = AddAllowedSenderEntry(ppRoot, ppLast, &allowIP, iSignificantBits)) != RS_RET_OK) { free(allowIP.addr.NetAddr); FINALIZE; } break; case AF_INET6: /* IPv6 - but need to check if it is a v6-mapped IPv4 */ if(IN6_IS_ADDR_V4MAPPED (&SIN6(res->ai_addr)->sin6_addr)) { /* extract & add IPv4 */ iSignificantBits = 32; allowIP.flags = 0; if((allowIP.addr.NetAddr = (struct sockaddr *) MALLOC(sizeof(struct sockaddr))) == NULL) { ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); } SIN(allowIP.addr.NetAddr)->sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN SIN(allowIP.addr.NetAddr)->sin_len = sizeof (struct sockaddr_in); #endif SIN(allowIP.addr.NetAddr)->sin_port = 0; memcpy(&(SIN(allowIP.addr.NetAddr)->sin_addr.s_addr), &(SIN6(res->ai_addr)->sin6_addr.s6_addr32[3]), sizeof (in_addr_t)); if((iRet = AddAllowedSenderEntry(ppRoot, ppLast, &allowIP, iSignificantBits)) != RS_RET_OK) { free(allowIP.addr.NetAddr); FINALIZE; } } else { /* finally add IPv6 */ iSignificantBits = 128; allowIP.flags = 0; if((allowIP.addr.NetAddr = MALLOC(res->ai_addrlen)) == NULL) { ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); } memcpy(allowIP.addr.NetAddr, res->ai_addr, res->ai_addrlen); if((iRet = AddAllowedSenderEntry(ppRoot, ppLast, &allowIP, iSignificantBits)) != RS_RET_OK) { free(allowIP.addr.NetAddr); FINALIZE; } } break; } } freeaddrinfo (restmp); } else { /* wildcards in hostname - we need to add a text-based ACL. * For this, we already have everything ready and just need * to pass it along... */ iRet = AddAllowedSenderEntry(ppRoot, ppLast, iAllow, iSignificantBits); } } finalize_it: RETiRet; }
static struct socket *getlist( void *arg, in_port_t lport, in_port_t fport, const struct sockaddr *local, const struct sockaddr *remote) { struct inpcb *head, pcbp; struct inpcbhead *pcbhead = arg; char *faddr, *laddr, *pfaddr, *pladdr; int alen; if (remote->sa_family != local->sa_family) return (NULL); switch (remote->sa_family) { case AF_INET: faddr = (char *)&SIN4(remote)->sin_addr; laddr = (char *)&SIN4(local)->sin_addr; break; case AF_INET6: faddr = (char *)&SIN6(remote)->sin6_addr; laddr = (char *)&SIN6(local)->sin6_addr; break; default: return (NULL); } head = pcbhead->lh_first; if (head == NULL) return (NULL); do { if (getbuf((u_long) head, &pcbp, sizeof(struct inpcb)) == -1) break; if (opt_enabled(PROXY) && remote->sa_family == AF_INET) { if (SIN4(remote)->sin_addr.s_addr == SIN4(&proxy)->sin_addr.s_addr && SIN4(local)->sin_addr.s_addr != SIN4(&proxy)->sin_addr.s_addr && pcbp.inp_fport == fport && pcbp.inp_lport == lport) { return (pcbp.inp_socket); } } if (remote->sa_family == AF_INET) { pfaddr = (char *)&pcbp.inp_faddr; pladdr = (char *)&pcbp.inp_laddr; alen = sizeof(struct in_addr); } else if (remote->sa_family == AF_INET6) { pfaddr = (char *)&pcbp.in6p_faddr; pladdr = (char *)&pcbp.in6p_laddr; alen = sizeof(struct in6_addr); } else continue; if (memcmp(pfaddr, faddr, alen) == 0 && memcmp(pladdr, laddr, alen) == 0 && pcbp.inp_fport == fport && pcbp.inp_lport == lport) { return (pcbp.inp_socket); } head = pcbp.inp_list.le_next; } while (head != NULL); return (NULL); }
/* Retrieve address information for the given ifp */ static int if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label) { int ret; struct lifreq lifreq; struct sockaddr_storage mask, dest; char *dest_pnt = NULL; u_char prefixlen = 0; afi_t af; int flags = 0; /* Interface's name and address family. * We need to use the logical interface name / label, if we've been * given one, in order to get the right address */ strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ); /* Interface's address. */ memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr)); af = addr->sa_family; /* Point to point or broad cast address pointer init. */ dest_pnt = NULL; if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0) { memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr)); if (af == AF_INET) dest_pnt = (char *) &(SIN (&dest)->sin_addr); else dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr); flags = ZEBRA_IFA_PEER; } if (af == AF_INET) { ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name, safe_strerror (errno)); return ret; } return 0; } memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr)); prefixlen = ip_masklen (SIN (&mask)->sin_addr); if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0)) { memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = (char *) &SIN (&dest)->sin_addr; } } #ifdef HAVE_IPV6 else if (af == AF_INET6) { if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0) { if (ifp->flags & IFF_POINTOPOINT) prefixlen = IPV6_MAX_BITLEN; else zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s", ifp->name, safe_strerror (errno)); } else { prefixlen = lifreq.lifr_addrlen; } } #endif /* HAVE_IPV6 */ /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen, (struct in_addr *) dest_pnt, label); #ifdef HAVE_IPV6 else if (af == AF_INET6) connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen, (struct in6_addr *) dest_pnt, label); #endif /* HAVE_IPV6 */ return 0; }
/*FUNCTION*------------------------------------------------------------- * * Function Name : getaddrinfo * Returned Value : RTCS_OK or error code * Comments : * Get a list of IP addresses and port numbers for host hostname and service servname. * *END*-----------------------------------------------------------------*/ int32_t getaddrinfo ( const char *hostname, /* host name or IP or NULL */ const char *servname, /* service name or port number */ const struct addrinfo *hints, /* set flags */ struct addrinfo **res /* [OUT]list of address structures */ ) { const char *proto = NULL; int family; int socktype; int flags; int protocol; struct addrinfo *ai; struct addrinfo *ai_list; uint16_t port; uint16_t err; uint16_t i; int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,int, int); /*hostname and send name can not be NULL in same time*/ if (hostname == NULL && servname == NULL) { return (EAI_NONAME); } proto = NULL; if (hints != NULL) { if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) { return (EAI_BADFLAGS); } if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) { _task_errno = MQX_EINVAL; return (EAI_SYSTEM); } family = hints->ai_family; socktype = hints->ai_socktype; protocol = hints->ai_protocol; flags = hints->ai_flags; /* looking for correct protocol depended on family and socket type */ switch (family) { case AF_UNSPEC: #if RTCSCFG_ENABLE_IP4 case AF_INET: #endif #if RTCSCFG_ENABLE_IP6 case AF_INET6: #endif if(hints->ai_socktype == 0) { break; }else if(hints->ai_socktype == SOCK_STREAM) { proto = "tcp"; }else if(hints->ai_socktype == SOCK_DGRAM) { proto = "udp"; }else{ return (EAI_SOCKTYPE); } break; default: return (EAI_FAMILY); }/* end of switch (family) */ } else { protocol = 0; family = 0; socktype = 0; flags = 0; }/* end of (hints != NULL) */ if(proto !=NULL) { protocol = (strcmp(proto,"tcp")) ? 2 : 1; } /* * Ok, only AF_INET and AF_INET6 left. */ /*************************************/ /* * First, look up the service port if it was * requested. If the socket type wasn't specified, then * try and figure it out. */ if (servname != NULL) { char *e; port = strtol(servname, &e, 10); if (*e == '\0') //*e - end pointer { /* Port number.*/ if (socktype == 0) //Not sure that it is necessary here { return (EAI_SOCKTYPE); } /* When port will be in network endian, do mqx_htons(&tmp,(uint16_t) port); */ } else { /* We use only port number. We do not use a service name */ return (EAI_SERVICE); }/*end of (*e == '\0')*/ } else { port = 0; } /* end (servname != NULL) */ /* * Next, deal with just a service name, and no hostname. * (we verified that one of them was non-null up above). */ ai_list = NULL; if (hostname == NULL && (flags & AI_PASSIVE) != 0) { #if RTCSCFG_ENABLE_IP4 if (family == AF_INET || family == 0) { /* Allocate an addrinfo structure, and a sockaddr structure */ ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); if (ai == NULL) { freeaddrinfo(ai_list); return (EAI_MEMORY); } ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN(ai->ai_addr)->sin_port = port; ai->ai_next = ai_list; ai_list = ai; } #endif #if RTCSCFG_ENABLE_IP6 if (family == AF_INET6 || family == 0) { ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); if (ai == NULL) { freeaddrinfo(ai_list); return (EAI_MEMORY); } ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN6(ai->ai_addr)->sin6_port = port; ai->ai_next = ai_list; ai_list = ai; } #endif *res = ai; return (0); }/* end of (hostname == NULL && (flags & AI_PASSIVE) != 0) */ /* * If the host is not NULL and the family isn't specified or AI_NUMERICHOST * specified, check first to see if it is a numeric address. * Though the gethostbyname2() routine * will recognize numeric addresses, it will only recognize * the format that it is being called for. Thus, a numeric * AF_INET address will be treated by the AF_INET6 call as * a domain name, and vice versa. Checking for both numerics * here avoids that. */ if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0)) { char abuf[sizeof(struct in6_addr)]; char nbuf[NI_MAXHOST]; int addrsize, addroff; char *p, *ep; char ntmp[NI_MAXHOST]; uint32_t scopeid; /* * Scope identifier portion. * scope id must be a decimal number */ ntmp[0] = '\0'; if (strchr(hostname, '%') != NULL) { strncpy(ntmp, hostname, sizeof(ntmp) - 1); ntmp[sizeof(ntmp) - 1] = '\0'; /*Returns a pointer to the first occurrence of character '%'.*/ p = strchr(ntmp, '%'); ep = NULL; /* * Vendors may want to support non-numeric * scopeid around here. */ if (p != NULL) { scopeid = (uint32_t)strtoul(p + 1, &ep, 10); } if (p != NULL && ep != NULL && ep[0] == '\0') { *p = '\0'; }else { ntmp[0] = '\0'; scopeid = 0; } } else{ scopeid = 0; } /* end of (strchr(hostname, '%') != NULL) */ /* * Converts a human readable IP address into an address * family appropriate 32bit or 128bit binary structure. */ if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf,sizeof( *((struct in_addr *)abuf)))== RTCS_OK) { if (family == AF_INET6) { /* * Convert to a V4 mapped address. */ struct in6_addr *a6 = (struct in6_addr *)abuf; memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4); memset(&a6->s6_addr[10], 0xff, 2); memset(&a6->s6_addr[0], 0, 10); goto inet6_addr; } addrsize = sizeof(struct in_addr); addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; family = AF_INET; goto common; } else if (ntmp[0] != '\0' && inet_pton(AF_INET6, ntmp, abuf,sizeof(struct in6_addr)) == RTCS_OK) { if (family && family != AF_INET6) { return (EAI_NONAME); } addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; goto common; } else if (inet_pton(AF_INET6, hostname, abuf,sizeof(struct in6_addr)) == RTCS_OK) { if (family != 0 && family != AF_INET6) { return (EAI_NONAME); } inet6_addr: addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; common: ai = ai_clone(ai_list, family); if (ai == NULL) { return (EAI_MEMORY); } ai_list = ai; ai->ai_socktype = socktype; //ai->ai_protocol = protocol; SIN(ai->ai_addr)->sin_port = port; memcpy((char *)ai->ai_addr + addroff, abuf, addrsize); if (flags & AI_CANONNAME) { if (ai->ai_family == AF_INET6) { SIN6(ai->ai_addr)->sin6_scope_id = scopeid; } if (getnameinfo( ai->ai_addr, ai->ai_addrlen, nbuf, sizeof(nbuf), NULL, 0, NI_NUMERICHOST ) == 0) { ai->ai_canonname = strdup(nbuf); if (ai->ai_canonname == NULL) { freeaddrinfo(ai_list); return (EAI_MEMORY); } } else { /* XXX raise error? */ ai->ai_canonname = NULL; } }/*end of (flags & AI_CANONNAME)*/ goto done; } else if ((flags & AI_NUMERICHOST) != 0) { return (EAI_NONAME); } }/* end of (inet_pton(AF_INET, hostname, (struct in_addr *)abuf)== 1) */ set_order(family, net_order); for (i = 0; i < FOUND_MAX; i++) { if (net_order[i] == NULL) break; err = (net_order[i])(hostname, flags, &ai_list, socktype, port); if (err != 0) return (err); } if (ai_list == NULL) return (EAI_NODATA); done: ai_list->ai_protocol = protocol; ai_list->ai_flags = flags; ai_list = ai_reverse(ai_list); *res = ai_list; return (0); }
/* Receive packet */ void l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer, struct sockaddr *sock, void *nat_t_ctx, u_char *pkt, int pktlen) { int i, len, offsiz, reqlen, is_ctrl; uint16_t mestype; struct l2tp_avp *avp, *avp0; l2tp_ctrl *ctrl; l2tp_call *call; char buf[L2TP_AVP_MAXSIZ], errmsg[256]; time_t curr_time; u_char *pkt0; struct l2tp_header hdr; char hbuf[NI_MAXHOST + NI_MAXSERV + 16]; ctrl = NULL; curr_time = get_monosec(); pkt0 = pkt; L2TP_CTRL_ASSERT(peer->sa_family == sock->sa_family); L2TP_CTRL_ASSERT(peer->sa_family == AF_INET || peer->sa_family == AF_INET6) /* * Parse L2TP Header */ memset(&hdr, 0, sizeof(hdr)); if (pktlen < 2) { snprintf(errmsg, sizeof(errmsg), "a short packet. " "length=%d", pktlen); goto bad_packet; } memcpy(&hdr, pkt, 2); pkt += 2; if (hdr.ver != L2TP_HEADER_VERSION_RFC2661) { /* XXX: only RFC2661 is supported */ snprintf(errmsg, sizeof(errmsg), "Unsupported version at header = %d", hdr.ver); goto bad_packet; } is_ctrl = (hdr.t != 0)? 1 : 0; /* calc required length */ reqlen = 6; /* for Flags, Tunnel-Id, Session-Id field */ if (hdr.l) reqlen += 2; /* for Length field (opt) */ if (hdr.s) reqlen += 4; /* for Ns, Nr field (opt) */ if (hdr.o) reqlen += 2; /* for Offset Size field (opt) */ if (reqlen > pktlen) { snprintf(errmsg, sizeof(errmsg), "a short packet. length=%d", pktlen); goto bad_packet; } if (hdr.l != 0) { GETSHORT(hdr.length, pkt); if (hdr.length > pktlen) { snprintf(errmsg, sizeof(errmsg), "Actual packet size is smaller than the length " "field %d < %d", pktlen, hdr.length); goto bad_packet; } pktlen = hdr.length; /* remove trailing trash */ } GETSHORT(hdr.tunnel_id, pkt); GETSHORT(hdr.session_id, pkt); if (hdr.s != 0) { GETSHORT(hdr.ns, pkt); GETSHORT(hdr.nr, pkt); } if (hdr.o != 0) { GETSHORT(offsiz, pkt); if (pktlen < offsiz) { snprintf(errmsg, sizeof(errmsg), "offset field is bigger than remaining packet " "length %d > %d", offsiz, pktlen); goto bad_packet; } pkt += offsiz; } L2TP_CTRL_ASSERT(pkt - pkt0 == reqlen); pktlen -= (pkt - pkt0); /* cut down the length of header */ ctrl = NULL; memset(buf, 0, sizeof(buf)); mestype = 0; avp = NULL; if (is_ctrl) { avp0 = (struct l2tp_avp *)buf; avp = avp_find_message_type_avp(avp0, pkt, pktlen); if (avp != NULL) mestype = avp->attr_value[0] << 8 | avp->attr_value[1]; } ctrl = l2tpd_get_ctrl(_this, hdr.tunnel_id); if (ctrl == NULL) { /* new control */ if (!is_ctrl) { snprintf(errmsg, sizeof(errmsg), "bad data message: tunnelId=%d is not " "found.", hdr.tunnel_id); goto bad_packet; } if (mestype != L2TP_AVP_MESSAGE_TYPE_SCCRQ) { snprintf(errmsg, sizeof(errmsg), "bad control message: tunnelId=%d is not " "found. mestype=%s", hdr.tunnel_id, avp_mes_type_string(mestype)); goto bad_packet; } if ((ctrl = l2tp_ctrl_create()) == NULL) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_create() failed: %m"); goto fail; } if (l2tp_ctrl_init(ctrl, _this, peer, sock, nat_t_ctx) != 0) { l2tp_ctrl_log(ctrl, LOG_ERR, "l2tp_ctrl_start() failed: %m"); goto fail; } ctrl->listener_index = listener_index; l2tp_ctrl_reload(ctrl); } else { /* * treat as an error if src address and port is not * match. (because it is potentially DoS attach) */ int notmatch = 0; if (ctrl->peer.ss_family != peer->sa_family) notmatch = 1; else if (peer->sa_family == AF_INET) { if (SIN(peer)->sin_addr.s_addr != SIN(&ctrl->peer)->sin_addr.s_addr || SIN(peer)->sin_port != SIN(&ctrl->peer)->sin_port) notmatch = 1; } else if (peer->sa_family == AF_INET6) { if (!IN6_ARE_ADDR_EQUAL(&(SIN6(peer)->sin6_addr), &(SIN6(&ctrl->peer)->sin6_addr)) || SIN6(peer)->sin6_port != SIN6(&ctrl->peer)->sin6_port) notmatch = 1; } if (notmatch) { snprintf(errmsg, sizeof(errmsg), "tunnelId=%u is already assigned for %s", hdr.tunnel_id, addrport_tostring( (struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf, sizeof(hbuf))); goto bad_packet; } } ctrl->last_rcv = curr_time; call = NULL; if (hdr.session_id != 0) { /* search l2tp_call by Session ID */ /* linear search is enough for this purpose */ len = slist_length(&ctrl->call_list); for (i = 0; i < len; i++) { call = slist_get(&ctrl->call_list, i); if (call->session_id == hdr.session_id) break; call = NULL; } } if (!is_ctrl) { int delayed = 0; /* L2TP data */ if (ctrl->state != L2TP_CTRL_STATE_ESTABLISHED) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received Data packet in '%s'", l2tp_ctrl_state_string(ctrl)); goto fail; } if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but it has no call. " "session_id=%u", hdr.session_id); goto fail; } L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "call=%u RECV ns=%u nr=%u snd_nxt=%u rcv_nxt=%u len=%d", call->id, hdr.ns, hdr.nr, call->snd_nxt, call->rcv_nxt, pktlen)); if (call->state != L2TP_CALL_STATE_ESTABLISHED){ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received a data packet but call is not " "established"); goto fail; } if (hdr.s != 0) { if (SEQ_LT(hdr.ns, call->rcv_nxt)) { if (SEQ_LT(hdr.ns, call->rcv_nxt - L2TP_CALL_DELAY_LIMIT)) { /* sequence number seems to be delayed */ /* XXX: need to log? */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive a out of sequence " "data packet: %u < %u.", hdr.ns, call->rcv_nxt)); return; } delayed = 1; } else { call->rcv_nxt = hdr.ns + 1; } } l2tp_call_ppp_input(call, pkt, pktlen, delayed); return; } if (hdr.s != 0) { L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2, "RECV %s ns=%u nr=%u snd_nxt=%u snd_una=%u rcv_nxt=%u " "len=%d", (is_ctrl)? "C" : "", hdr.ns, hdr.nr, ctrl->snd_nxt, ctrl->snd_una, ctrl->rcv_nxt, pktlen)); if (pktlen <= 0) l2tp_ctrl_log(ctrl, LOG_INFO, "RecvZLB"); if (SEQ_GT(hdr.nr, ctrl->snd_una)) { if (hdr.nr == ctrl->snd_nxt || SEQ_LT(hdr.nr, ctrl->snd_nxt)) ctrl->snd_una = hdr.nr; else { l2tp_ctrl_log(ctrl, LOG_INFO, "Received message has bad Nr field: " "%u < %u.", hdr.ns, ctrl->snd_nxt); /* XXX Drop with ZLB? */ goto fail; } } if (l2tp_ctrl_txwin_size(ctrl) <= 0) { /* no waiting ack */ if (ctrl->hello_wait_ack != 0) { /* * Reset Hello state, as an ack for the Hello * is recived. */ ctrl->hello_wait_ack = 0; ctrl->hello_io_time = curr_time; } switch (ctrl->state) { case L2TP_CTRL_STATE_CLEANUP_WAIT: l2tp_ctrl_stop(ctrl, 0); return; } } if (hdr.ns != ctrl->rcv_nxt) { /* there are remaining packet */ if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) { /* resend or sent ZLB */ l2tp_ctrl_send_ZLB(ctrl); } #ifdef L2TP_CTRL_DEBUG if (pktlen != 0) { /* not ZLB */ L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "receive out of sequence %u must be %u. " "mestype=%s", hdr.ns, ctrl->rcv_nxt, avp_mes_type_string(mestype))); } #endif return; } if (pktlen <= 0) return; /* ZLB */ if (l2tp_ctrl_txwin_is_full(ctrl)) { L2TP_CTRL_DBG((ctrl, LOG_DEBUG, "Received message cannot be handled. " "Transmission window is full.")); l2tp_ctrl_send_ZLB(ctrl); return; } ctrl->rcv_nxt++; if (avp == NULL) { l2tpd_log(_this, LOG_WARNING, "bad control message: no message-type AVP."); goto fail; } } /* * state machine (RFC2661 pp. 56-57) */ switch (ctrl->state) { case L2TP_CTRL_STATE_IDLE: switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCRQ: if (l2tp_ctrl_recv_SCCRQ(ctrl, pkt, pktlen, _this, peer) == 0) { /* acceptable */ l2tp_ctrl_send_SCCRP(ctrl); ctrl->state = L2TP_CTRL_STATE_WAIT_CTL_CONN; return; } /* * in case un-acceptable, it was already processed * at l2tcp_ctrl_recv_SCCRQ */ return; case L2TP_AVP_MESSAGE_TYPE_SCCRP: /* * RFC specifies that sent of StopCCN in the state, * However as this implementation only support Passive * open, this packet will not received. */ /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_SCCCN: default: break; } goto fsm_fail; case L2TP_CTRL_STATE_WAIT_CTL_CONN: /* Wait-Ctl-Conn */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: l2tp_ctrl_log(ctrl, LOG_INFO, "RecvSCCN"); if (l2tp_ctrl_send_ZLB(ctrl) == 0) { ctrl->state = L2TP_CTRL_STATE_ESTABLISHED; } return; case L2TP_AVP_MESSAGE_TYPE_StopCCN: goto receive_stop_ccn; case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_ESTABLISHED: /* Established */ switch (mestype) { case L2TP_AVP_MESSAGE_TYPE_SCCCN: case L2TP_AVP_MESSAGE_TYPE_SCCRQ: case L2TP_AVP_MESSAGE_TYPE_SCCRP: break; receive_stop_ccn: case L2TP_AVP_MESSAGE_TYPE_StopCCN: if (l2tp_ctrl_recv_StopCCN(ctrl, pkt, pktlen) == 0) { if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; } l2tp_ctrl_log(ctrl, LOG_ERR, "Received bad StopCCN"); l2tp_ctrl_send_ZLB(ctrl); l2tp_ctrl_stop(ctrl, 0); return; case L2TP_AVP_MESSAGE_TYPE_HELLO: if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) l2tp_ctrl_send_ZLB(ctrl); return; case L2TP_AVP_MESSAGE_TYPE_CDN: case L2TP_AVP_MESSAGE_TYPE_ICRP: case L2TP_AVP_MESSAGE_TYPE_ICCN: if (call == NULL) { l2tp_ctrl_log(ctrl, LOG_INFO, "Unknown call message: %s", avp_mes_type_string(mestype)); goto fail; } /* FALLTHROUGH */ case L2TP_AVP_MESSAGE_TYPE_ICRQ: l2tp_call_recv_packet(ctrl, call, mestype, pkt, pktlen); return; default: break; } break; /* fsm_fail */ case L2TP_CTRL_STATE_CLEANUP_WAIT: if (mestype == L2TP_AVP_MESSAGE_TYPE_StopCCN) { /* * We left ESTABLISHED state, but the peer sent StopCCN. */ goto receive_stop_ccn; } break; /* fsm_fail */ } fsm_fail: /* state machine error */ l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_FSM_ERROR); return; fail: if (ctrl != NULL && mestype != 0) { l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state", avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl)); l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_GENERAL_ERROR); } return; bad_packet: l2tpd_log(_this, LOG_INFO, "Received from=%s: %s", addrport_tostring(peer, peer->sa_len, hbuf, sizeof(hbuf)), errmsg); return; }
/** Delete the IPsec SA for disconnection */ static void l2tp_ctrl_purge_ipsec_sa(l2tp_ctrl *_this) { int is_natt, proto; struct sockaddr_storage peer, sock; hash_link *hl; #ifdef USE_LIBSOCKUTIL struct in_ipsec_sa_cookie *ipsec_sa_cookie; #endif l2tp_ctrl *anot; /* * Search another tunnel that uses the same IPsec SA * by lineer. */ for (hl = hash_first(_this->l2tpd->ctrl_map); hl != NULL; hl = hash_next(_this->l2tpd->ctrl_map)) { anot = hl->item; if (anot == _this) continue; if (_this->peer.ss_family != anot->peer.ss_family) continue; if (_this->peer.ss_family == AF_INET) { if (SIN(&_this->peer)->sin_addr.s_addr != SIN(&anot->peer)->sin_addr.s_addr) continue; } else if (_this->peer.ss_family == AF_INET6) { if (!IN6_ARE_ADDR_EQUAL( &(SIN6(&_this->peer)->sin6_addr), &(SIN6(&anot->peer)->sin6_addr))) continue; } #ifdef USE_LIBSOCKUTIL if (_this->sa_cookie != NULL && anot->sa_cookie != NULL) { /* Both tunnels belong the same NAT box. */ if (memcmp(_this->sa_cookie, anot->sa_cookie, sizeof(struct in_ipsec_sa_cookie)) != 0) /* Different hosts behind the NAT box. */ continue; /* The SA is shared by another tunnels by one host. */ return; /* don't purge the sa */ } else if (_this->sa_cookie != NULL || anot->sa_cookie != NULL) /* Only one is behind the NAT */ continue; #endif return; /* don't purge the sa */ } #if defined(USE_LIBSOCKUTIL) && defined(IP_IPSEC_SA_COOKIE) is_natt = (_this->sa_cookie != NULL)? 1 : 0; #else is_natt = 0; #endif proto = 0; memcpy(&peer, &_this->peer, _this->peer.ss_len); memcpy(&sock, &_this->sock, _this->sock.ss_len); if (!is_natt) SIN(&peer)->sin_port = SIN(&sock)->sin_port = 0; #if defined(USE_LIBSOCKUTIL) && defined(IP_IPSEC_SA_COOKIE) else { ipsec_sa_cookie = _this->sa_cookie; SIN(&peer)->sin_port = ipsec_sa_cookie->remote_port; SIN(&sock)->sin_port = ipsec_sa_cookie->local_port; #if 1 /* * XXX: As RFC 2367, protocol sould be specified if the port * XXX: number is non-zero. */ proto = 0; #else proto = IPPROTO_UDP; #endif } #endif if (ipsec_util_purge_transport_sa((struct sockaddr *)&peer, (struct sockaddr *)&sock, proto, IPSEC_UTIL_DIRECTION_BOTH) != 0) l2tp_ctrl_log(_this, LOG_NOTICE, "failed to purge IPSec SA"); }
void sin_set_port(struct sockaddr_storage *ss, in_port_t port) { if (ss->ss_family == AF_INET6) SIN6(ss)->sin6_port = port; SIN4(ss)->sin_port = port; }
char * get_next_msg(char *buf, char *lim, size_t *lenp) { struct rt_msghdr *rtm; struct ifa_msghdr *ifam; struct sockaddr *sa, *dst, *ifa, *rti_info[RTAX_MAX]; *lenp = 0; for (rtm = (struct rt_msghdr *)buf; rtm < (struct rt_msghdr *)lim; rtm = (struct rt_msghdr *)((char *)rtm + rtm->rtm_msglen)) { /* just for safety */ if (!rtm->rtm_msglen) { log_warnx("rtm_msglen is 0 (buf=%p lim=%p rtm=%p)", buf, lim, rtm); break; } if (rtm->rtm_version != RTM_VERSION) continue; switch (rtm->rtm_type) { case RTM_ADD: case RTM_DELETE: if (rtm->rtm_tableid != 0) continue; /* address related checks */ sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); if ((dst = rti_info[RTAX_DST]) == NULL || dst->sa_family != AF_INET6) continue; if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) continue; if (rti_info[RTAX_NETMASK] == NULL) continue; /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_NEWADDR: case RTM_DELADDR: ifam = (struct ifa_msghdr *)rtm; /* address related checks */ sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen); get_rtaddrs(ifam->ifam_addrs, sa, rti_info); if ((ifa = rti_info[RTAX_IFA]) == NULL || (ifa->sa_family != AF_INET && ifa->sa_family != AF_INET6)) continue; if (ifa->sa_family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) continue; /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ case RTM_IFINFO: /* found */ *lenp = rtm->rtm_msglen; return (char *)rtm; /* NOTREACHED */ } } return (char *)rtm; }
/*% * Get a list of IP addresses and port numbers for host hostname and * service servname. */ int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct servent *sp; const char *proto; int family, socktype, flags, protocol; struct addrinfo *ai, *ai_list; int err = 0; int port, i; int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **, int, int); if (hostname == NULL && servname == NULL) return (EAI_NONAME); proto = NULL; if (hints != NULL) { if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0) return (EAI_BADFLAGS); if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) { errno = EINVAL; return (EAI_SYSTEM); } family = hints->ai_family; socktype = hints->ai_socktype; protocol = hints->ai_protocol; flags = hints->ai_flags; switch (family) { case AF_UNSPEC: switch (hints->ai_socktype) { case SOCK_STREAM: proto = "tcp"; break; case SOCK_DGRAM: proto = "udp"; break; } break; case AF_INET: case AF_INET6: switch (hints->ai_socktype) { case 0: break; case SOCK_STREAM: proto = "tcp"; break; case SOCK_DGRAM: proto = "udp"; break; case SOCK_RAW: break; default: return (EAI_SOCKTYPE); } break; #ifdef AF_LOCAL case AF_LOCAL: switch (hints->ai_socktype) { case 0: break; case SOCK_STREAM: break; case SOCK_DGRAM: break; default: return (EAI_SOCKTYPE); } break; #endif default: return (EAI_FAMILY); } } else { protocol = 0; family = 0; socktype = 0; flags = 0; } #ifdef AF_LOCAL /*! * First, deal with AF_LOCAL. If the family was not set, * then assume AF_LOCAL if the first character of the * hostname/servname is '/'. */ if (hostname != NULL && (family == AF_LOCAL || (family == 0 && *hostname == '/'))) return (get_local(hostname, socktype, res)); if (servname != NULL && (family == AF_LOCAL || (family == 0 && *servname == '/'))) return (get_local(servname, socktype, res)); #endif /* * Ok, only AF_INET and AF_INET6 left. */ ai_list = NULL; /* * First, look up the service name (port) if it was * requested. If the socket type wasn't specified, then * try and figure it out. */ if (servname != NULL) { char *e; port = strtol(servname, &e, 10); if (*e == '\0') { if (socktype == 0) return (EAI_SOCKTYPE); if (port < 0 || port > 65535) return (EAI_SERVICE); port = htons((unsigned short) port); } else { sp = getservbyname(servname, proto); if (sp == NULL) return (EAI_SERVICE); port = sp->s_port; if (socktype == 0) { if (strcmp(sp->s_proto, "tcp") == 0) socktype = SOCK_STREAM; else if (strcmp(sp->s_proto, "udp") == 0) socktype = SOCK_DGRAM; } } } else port = 0; /* * Next, deal with just a service name, and no hostname. * (we verified that one of them was non-null up above). */ if (hostname == NULL && (flags & AI_PASSIVE) != 0) { if (family == AF_INET || family == 0) { ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in)); if (ai == NULL) return (EAI_MEMORY); ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN(ai->ai_addr)->sin_port = port; ai->ai_next = ai_list; ai_list = ai; } if (family == AF_INET6 || family == 0) { ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6)); if (ai == NULL) { _freeaddrinfo(ai_list); return (EAI_MEMORY); } ai->ai_socktype = socktype; ai->ai_protocol = protocol; SIN6(ai->ai_addr)->sin6_port = port; ai->ai_next = ai_list; ai_list = ai; } *res = ai_list; return (0); } /* * If the family isn't specified or AI_NUMERICHOST specified, check * first to see if it is a numeric address. * Though the gethostbyname2() routine will recognize numeric addresses, * it will only recognize the format that it is being called for. Thus, * a numeric AF_INET address will be treated by the AF_INET6 call as * a domain name, and vice versa. Checking for both numerics here * avoids that. */ if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0)) { char abuf[sizeof(struct in6_addr)]; char nbuf[NI_MAXHOST]; int addrsize, addroff; #ifdef IRS_HAVE_SIN6_SCOPE_ID char *p, *ep; char ntmp[NI_MAXHOST]; isc_uint32_t scopeid; #endif #ifdef IRS_HAVE_SIN6_SCOPE_ID /* * Scope identifier portion. */ ntmp[0] = '\0'; if (strchr(hostname, '%') != NULL) { strncpy(ntmp, hostname, sizeof(ntmp) - 1); ntmp[sizeof(ntmp) - 1] = '\0'; p = strchr(ntmp, '%'); ep = NULL; /* * Vendors may want to support non-numeric * scopeid around here. */ if (p != NULL) scopeid = (isc_uint32_t)strtoul(p + 1, &ep, 10); if (p != NULL && ep != NULL && ep[0] == '\0') *p = '\0'; else { ntmp[0] = '\0'; scopeid = 0; } } else scopeid = 0; #endif if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf) == 1) { if (family == AF_INET6) { /* * Convert to a V4 mapped address. */ struct in6_addr *a6 = (struct in6_addr *)abuf; memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4); memset(&a6->s6_addr[10], 0xff, 2); memset(&a6->s6_addr[0], 0, 10); goto inet6_addr; } addrsize = sizeof(struct in_addr); addroff = (char *)(&SIN(0)->sin_addr) - (char *)0; family = AF_INET; goto common; #ifdef IRS_HAVE_SIN6_SCOPE_ID } else if (ntmp[0] != '\0' && inet_pton(AF_INET6, ntmp, abuf) == 1) { if (family && family != AF_INET6) return (EAI_NONAME); addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; goto common; #endif } else if (inet_pton(AF_INET6, hostname, abuf) == 1) { if (family != 0 && family != AF_INET6) return (EAI_NONAME); inet6_addr: addrsize = sizeof(struct in6_addr); addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0; family = AF_INET6; common: ai = ai_alloc(family, ((family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))); if (ai == NULL) return (EAI_MEMORY); ai_list = ai; ai->ai_socktype = socktype; SIN(ai->ai_addr)->sin_port = port; memmove((char *)ai->ai_addr + addroff, abuf, addrsize); if ((flags & AI_CANONNAME) != 0) { #ifdef IRS_HAVE_SIN6_SCOPE_ID if (ai->ai_family == AF_INET6) SIN6(ai->ai_addr)->sin6_scope_id = scopeid; #endif if (getnameinfo(ai->ai_addr, (socklen_t)ai->ai_addrlen, nbuf, sizeof(nbuf), NULL, 0, NI_NUMERICHOST) == 0) { ai->ai_canonname = strdup(nbuf); if (ai->ai_canonname == NULL) { _freeaddrinfo(ai); return (EAI_MEMORY); } } else { /* XXX raise error? */ ai->ai_canonname = NULL; } } goto done; } else if ((flags & AI_NUMERICHOST) != 0) { return (EAI_NONAME); } } if (hostname == NULL && (flags & AI_PASSIVE) == 0) { set_order(family, net_order); for (i = 0; i < FOUND_MAX; i++) { if (net_order[i] == NULL) break; err = (net_order[i])(hostname, flags, &ai_list, socktype, port); if (err != 0) { if (ai_list != NULL) { _freeaddrinfo(ai_list); ai_list = NULL; } break; } } } else err = resolve_name(family, hostname, flags, &ai_list, socktype, port); if (ai_list == NULL) { if (err == 0) err = EAI_NONAME; return (err); } done: ai_list = ai_reverse(ai_list); *res = ai_list; return (0); }
static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip, int socktype, int port) { struct addrinfo *ai; lwres_context_t *lwrctx = NULL; lwres_gabnresponse_t *by = NULL; lwres_addr_t *addr; lwres_result_t lwres; int result = 0; lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); if (lwres != LWRES_R_SUCCESS) ERR(EAI_FAIL); (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); if (hostname == NULL && (flags & AI_PASSIVE) == 0) { ai = ai_clone(*aip, AF_INET6); if (ai == NULL) { lwres_freeaddrinfo(*aip); ERR(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN6(ai->ai_addr)->sin6_port = port; memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16); } else { lwres = lwres_getaddrsbyname(lwrctx, hostname, LWRES_ADDRTYPE_V6, &by); if (lwres != LWRES_R_SUCCESS) { if (lwres == LWRES_R_NOTFOUND) goto cleanup; else ERR(EAI_FAIL); } addr = LWRES_LIST_HEAD(by->addrs); while (addr != NULL) { ai = ai_clone(*aip, AF_INET6); if (ai == NULL) { lwres_freeaddrinfo(*aip); ERR(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN6(ai->ai_addr)->sin6_port = port; memcpy(&SIN6(ai->ai_addr)->sin6_addr, addr->address, 16); if (flags & AI_CANONNAME) { ai->ai_canonname = strdup(by->realname); if (ai->ai_canonname == NULL) ERR(EAI_MEMORY); } addr = LWRES_LIST_NEXT(addr, link); } } cleanup: if (by != NULL) lwres_gabnresponse_free(lwrctx, &by); if (lwrctx != NULL) { lwres_conf_clear(lwrctx); lwres_context_destroy(&lwrctx); } return (result); }