📄 addr_families.c
字号:
/* * Copyright (c) 1997-2007 Kungliga Tekniska H鰃skolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "krb5_locl.h"RCSID("$Id: addr_families.c 22039 2007-11-10 11:47:35Z lha $");struct addr_operations { int af; krb5_address_type atype; size_t max_sockaddr_size; krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, krb5_socklen_t *sa_size, int port); void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int); krb5_error_code (*h_addr2addr)(const char *, krb5_address *); krb5_boolean (*uninteresting)(const struct sockaddr *); void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int); int (*print_addr)(const krb5_address *, char *, size_t); int (*parse_addr)(krb5_context, const char*, krb5_address *); int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*); int (*free_addr)(krb5_context, krb5_address*); int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*); int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long, krb5_address*, krb5_address*);};/* * AF_INET - aka IPv4 implementation */static krb5_error_codeipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a){ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; unsigned char buf[4]; a->addr_type = KRB5_ADDRESS_INET; memcpy (buf, &sin4->sin_addr, 4); return krb5_data_copy(&a->address, buf, 4);}static krb5_error_codeipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port){ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; *port = sin4->sin_port; return 0;}static voidipv4_addr2sockaddr (const krb5_address *a, struct sockaddr *sa, krb5_socklen_t *sa_size, int port){ struct sockaddr_in tmp; memset (&tmp, 0, sizeof(tmp)); tmp.sin_family = AF_INET; memcpy (&tmp.sin_addr, a->address.data, 4); tmp.sin_port = port; memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); *sa_size = sizeof(tmp);}static voidipv4_h_addr2sockaddr(const char *addr, struct sockaddr *sa, krb5_socklen_t *sa_size, int port){ struct sockaddr_in tmp; memset (&tmp, 0, sizeof(tmp)); tmp.sin_family = AF_INET; tmp.sin_port = port; tmp.sin_addr = *((const struct in_addr *)addr); memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); *sa_size = sizeof(tmp);}static krb5_error_codeipv4_h_addr2addr (const char *addr, krb5_address *a){ unsigned char buf[4]; a->addr_type = KRB5_ADDRESS_INET; memcpy(buf, addr, 4); return krb5_data_copy(&a->address, buf, 4);}/* * Are there any addresses that should be considered `uninteresting'? */static krb5_booleanipv4_uninteresting (const struct sockaddr *sa){ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa; if (sin4->sin_addr.s_addr == INADDR_ANY) return TRUE; return FALSE;}static voidipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port){ struct sockaddr_in tmp; memset (&tmp, 0, sizeof(tmp)); tmp.sin_family = AF_INET; tmp.sin_port = port; tmp.sin_addr.s_addr = INADDR_ANY; memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); *sa_size = sizeof(tmp);}static intipv4_print_addr (const krb5_address *addr, char *str, size_t len){ struct in_addr ia; memcpy (&ia, addr->address.data, 4); return snprintf (str, len, "IPv4:%s", inet_ntoa(ia));}static intipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr){ const char *p; struct in_addr a; p = strchr(address, ':'); if(p) { p++; if(strncasecmp(address, "ip:", p - address) != 0 && strncasecmp(address, "ip4:", p - address) != 0 && strncasecmp(address, "ipv4:", p - address) != 0 && strncasecmp(address, "inet:", p - address) != 0) return -1; } else p = address;#ifdef HAVE_INET_ATON if(inet_aton(p, &a) == 0) return -1;#elif defined(HAVE_INET_ADDR) a.s_addr = inet_addr(p); if(a.s_addr == INADDR_NONE) return -1;#else return -1;#endif addr->addr_type = KRB5_ADDRESS_INET; if(krb5_data_alloc(&addr->address, 4) != 0) return -1; _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); return 0;}static intipv4_mask_boundary(krb5_context context, const krb5_address *inaddr, unsigned long len, krb5_address *low, krb5_address *high){ unsigned long ia; uint32_t l, h, m = 0xffffffff; if (len > 32) { krb5_set_error_string(context, "IPv4 prefix too large (%ld)", len); return KRB5_PROG_ATYPE_NOSUPP; } m = m << (32 - len); _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length); l = ia & m; h = l | ~m; low->addr_type = KRB5_ADDRESS_INET; if(krb5_data_alloc(&low->address, 4) != 0) return -1; _krb5_put_int(low->address.data, l, low->address.length); high->addr_type = KRB5_ADDRESS_INET; if(krb5_data_alloc(&high->address, 4) != 0) { krb5_free_address(context, low); return -1; } _krb5_put_int(high->address.data, h, high->address.length); return 0;}/* * AF_INET6 - aka IPv6 implementation */#ifdef HAVE_IPV6static krb5_error_codeipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a){ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { unsigned char buf[4]; a->addr_type = KRB5_ADDRESS_INET;#ifndef IN6_ADDR_V6_TO_V4#ifdef IN6_EXTRACT_V4ADDR#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x))#else#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12])#endif#endif memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4); return krb5_data_copy(&a->address, buf, 4); } else { a->addr_type = KRB5_ADDRESS_INET6; return krb5_data_copy(&a->address, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); }}static krb5_error_codeipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port){ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; *port = sin6->sin6_port; return 0;}static voidipv6_addr2sockaddr (const krb5_address *a, struct sockaddr *sa, krb5_socklen_t *sa_size, int port){ struct sockaddr_in6 tmp; memset (&tmp, 0, sizeof(tmp)); tmp.sin6_family = AF_INET6; memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr)); tmp.sin6_port = port; memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); *sa_size = sizeof(tmp);}static voidipv6_h_addr2sockaddr(const char *addr, struct sockaddr *sa, krb5_socklen_t *sa_size, int port){ struct sockaddr_in6 tmp; memset (&tmp, 0, sizeof(tmp)); tmp.sin6_family = AF_INET6; tmp.sin6_port = port; tmp.sin6_addr = *((const struct in6_addr *)addr); memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); *sa_size = sizeof(tmp);}static krb5_error_codeipv6_h_addr2addr (const char *addr, krb5_address *a){ a->addr_type = KRB5_ADDRESS_INET6; return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr));}/* * */static krb5_booleanipv6_uninteresting (const struct sockaddr *sa){ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; return IN6_IS_ADDR_LINKLOCAL(in6) || IN6_IS_ADDR_V4COMPAT(in6);}static voidipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port){ struct sockaddr_in6 tmp; memset (&tmp, 0, sizeof(tmp)); tmp.sin6_family = AF_INET6; tmp.sin6_port = port; tmp.sin6_addr = in6addr_any; *sa_size = sizeof(tmp);}static intipv6_print_addr (const krb5_address *addr, char *str, size_t len){ char buf[128], buf2[3];#ifdef HAVE_INET_NTOP if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL)#endif { /* XXX this is pretty ugly, but better than abort() */ int i; unsigned char *p = addr->address.data; buf[0] = '\0'; for(i = 0; i < addr->address.length; i++) { snprintf(buf2, sizeof(buf2), "%02x", p[i]); if(i > 0 && (i & 1) == 0) strlcat(buf, ":", sizeof(buf)); strlcat(buf, buf2, sizeof(buf)); } } return snprintf(str, len, "IPv6:%s", buf);}static intipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr){ int ret; struct in6_addr in6; const char *p; p = strchr(address, ':'); if(p) { p++; if(strncasecmp(address, "ip6:", p - address) == 0 || strncasecmp(address, "ipv6:", p - address) == 0 || strncasecmp(address, "inet6:", p - address) == 0) address = p; } ret = inet_pton(AF_INET6, address, &in6.s6_addr); if(ret == 1) { addr->addr_type = KRB5_ADDRESS_INET6; ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); if (ret) return -1; memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); return 0; } return -1;}static intipv6_mask_boundary(krb5_context context, const krb5_address *inaddr, unsigned long len, krb5_address *low, krb5_address *high){ struct in6_addr addr, laddr, haddr; uint32_t m; int i, sub_len; if (len > 128) { krb5_set_error_string(context, "IPv6 prefix too large (%ld)", len); return KRB5_PROG_ATYPE_NOSUPP; } if (inaddr->address.length != sizeof(addr)) { krb5_set_error_string(context, "IPv6 addr bad length"); return KRB5_PROG_ATYPE_NOSUPP; } memcpy(&addr, inaddr->address.data, inaddr->address.length); for (i = 0; i < 16; i++) { sub_len = min(8, len); m = 0xff << (8 - sub_len); laddr.s6_addr[i] = addr.s6_addr[i] & m; haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m; if (len > 8) len -= 8; else len = 0; } low->addr_type = KRB5_ADDRESS_INET6; if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0) return -1; memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr)); high->addr_type = KRB5_ADDRESS_INET6; if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) { krb5_free_address(context, low); return -1; } memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr)); return 0;}#endif /* IPv6 *//* * table */#define KRB5_ADDRESS_ARANGE (-100)struct arange { krb5_address low; krb5_address high;};static intarange_parse_addr (krb5_context context, const char *address, krb5_address *addr){ char buf[1024], *p; krb5_address low0, high0; struct arange *a; krb5_error_code ret; if(strncasecmp(address, "RANGE:", 6) != 0) return -1; address += 6; p = strrchr(address, '/'); if (p) { krb5_addresses addrmask; char *q; long num; if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf)) return -1; buf[p - address] = '\0'; ret = krb5_parse_address(context, buf, &addrmask); if (ret) return ret; if(addrmask.len != 1) { krb5_free_addresses(context, &addrmask); return -1; } address += p - address + 1; num = strtol(address, &q, 10); if (q == address || *q != '\0' || num < 0) { krb5_free_addresses(context, &addrmask); return -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -