807 lines
18 KiB
C++
807 lines
18 KiB
C++
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <endian.h>
|
|
#include <string.h>
|
|
#include <alloca.h>
|
|
#include <ctype.h>
|
|
#include <pthread.h>
|
|
#include <netdb.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <net/if.h>
|
|
|
|
#include "sockaddr.h"
|
|
|
|
static inline int has2colon(const char *name) {
|
|
char c;
|
|
while( (c=*name++) != '\0' ) {
|
|
if(c==':') {
|
|
while( (c=*name++) != '\0' ) {
|
|
if(c==':')
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static unsigned short name2port(const char *name, int type) {
|
|
const char *proto = type==SOCK_STREAM?"tcp":"udp";
|
|
char buf[1024];
|
|
struct servent result_buf;
|
|
struct servent *result = NULL;
|
|
const char *p = strchr(name, '/');
|
|
if(p) {
|
|
int len = p - name;
|
|
char localname[len+1];
|
|
memcpy(localname, name, len);
|
|
localname[len] = 0;
|
|
getservbyname_r(localname, proto, &result_buf, buf, sizeof(buf), &result);
|
|
} else {
|
|
getservbyname_r(name, proto, &result_buf, buf, sizeof(buf), &result);
|
|
}
|
|
if(result == NULL)
|
|
return 0;
|
|
return ntohs(result_buf.s_port);
|
|
}
|
|
|
|
static unsigned int ip2addr(const char *name) {
|
|
if(name[0]=='*')
|
|
return 0;
|
|
|
|
struct in_addr addr;
|
|
const char *p = strrchr(name, ':');
|
|
if(p==NULL) p = strchr(name, '/');
|
|
if(p==NULL)
|
|
{
|
|
if(inet_pton(AF_INET, name, &addr) <= 0)
|
|
return INADDR_NONE;
|
|
} else {
|
|
int len = p - name;
|
|
char localname[len+1];
|
|
memcpy(localname, name, len);
|
|
localname[len] = 0;
|
|
if(inet_pton(AF_INET, localname, &addr) <= 0)
|
|
return INADDR_NONE;
|
|
}
|
|
|
|
unsigned int v = ntohl(addr.s_addr);
|
|
if(v < 0x0100000)
|
|
return INADDR_NONE;
|
|
|
|
return addr.s_addr;
|
|
}
|
|
|
|
static pthread_mutex_t lifr = PTHREAD_MUTEX_INITIALIZER;
|
|
static int nifr = 0;
|
|
struct ifreq * volatile ifr = NULL;
|
|
|
|
// clear interface information cache
|
|
// if module unloaded
|
|
__attribute__((__destructor__))
|
|
static void clean_ifr_cache(void) {
|
|
if(ifr != NULL) {
|
|
free(ifr);
|
|
ifr = NULL;
|
|
}
|
|
}
|
|
|
|
static int getintflist(void) {
|
|
if(ifr != NULL) return 0;
|
|
pthread_mutex_lock(&lifr);
|
|
if(ifr == NULL) {
|
|
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if( fd >= 0) {
|
|
struct ifconf ifc;
|
|
|
|
ifc.ifc_len = 0;
|
|
ifc.ifc_req = NULL;
|
|
if(ioctl(fd, SIOCGIFCONF, &ifc)==0)
|
|
{
|
|
ifr = (struct ifreq *)malloc(ifc.ifc_len>128?ifc.ifc_len:128);
|
|
ifc.ifc_req = ifr;
|
|
if(ioctl(fd, SIOCGIFCONF, &ifc)==0)
|
|
nifr = ifc.ifc_len / sizeof(struct ifreq);
|
|
}
|
|
close(fd);
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&lifr);
|
|
return ifr == NULL ? -1 : 0;
|
|
}
|
|
|
|
static int is_local_ipv4(uint32_t addr) {
|
|
if(addr==0) return 1;
|
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
|
if((addr >> 24) == 127)
|
|
return 1;
|
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
|
if((addr & 0xFF) == 127)
|
|
return 1;
|
|
#endif
|
|
|
|
if(getintflist() < 0)
|
|
return 0;
|
|
|
|
int i;
|
|
for(i=0; i<nifr; i++)
|
|
{
|
|
if(ifr[i].ifr_addr.sa_family==AF_INET) {
|
|
if(addr == ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr.s_addr)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int intf2addr(const char *name, uint32_t addr[4])
|
|
{
|
|
if(getintflist() < 0)
|
|
return 0;
|
|
|
|
int i;
|
|
for(i=0; i<nifr; i++)
|
|
{
|
|
if(strncmp(ifr[i].ifr_name, name, sizeof(ifr[i].ifr_name))!=0)
|
|
continue;
|
|
|
|
if(ifr[i].ifr_addr.sa_family==AF_INET) {
|
|
addr[0] = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr.s_addr;
|
|
return AF_INET;
|
|
}
|
|
// never happend, SIOCGIFCONF only applicable to IPv4
|
|
if(ifr[i].ifr_addr.sa_family==AF_INET6) {
|
|
memcpy(addr, ((struct sockaddr_in6 *)&ifr[i].ifr_addr)->sin6_addr.s6_addr, 16);
|
|
return AF_INET6;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int host2addr(const char *name, uint32_t addr[4])
|
|
{
|
|
char buf[1024];
|
|
struct hostent ret;
|
|
struct hostent *result = NULL;
|
|
int err;
|
|
|
|
gethostbyname_r(name, &ret, buf, sizeof(buf), &result, &err);
|
|
if(result != NULL) {
|
|
if(ret.h_addrtype==AF_INET && ret.h_length==4) {
|
|
memcpy(addr, ret.h_addr, 4);
|
|
return AF_INET;
|
|
} else if(ret.h_addrtype==AF_INET6 && ret.h_length==16) {
|
|
memcpy(addr, ret.h_addr, 16);
|
|
return AF_INET6;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int name2addr(const char *name, uint32_t addr[4])
|
|
{
|
|
int family;
|
|
|
|
family = intf2addr(name, addr);
|
|
if(family != 0) return family;
|
|
|
|
family = host2addr(name, addr);
|
|
if(family != 0) return family;
|
|
|
|
return family;
|
|
}
|
|
|
|
void CSocketAddress::BuildNameNone(void) {
|
|
sockname[0] = 0;
|
|
}
|
|
|
|
void CSocketAddress::BuildNameUnix(void) {
|
|
snprintf(sockname, sizeof(sockname), "%c%.*s",
|
|
un->sun_path[0]?:'@', (int)sizeof(un->sun_path)-1, un->sun_path+1);
|
|
}
|
|
|
|
void CSocketAddress::BuildNameIpv4(void) {
|
|
char ip[32];
|
|
if(in4->sin_addr.s_addr==0) {
|
|
// wild address is *
|
|
ip[0] = '*';
|
|
ip[1] = '\0';
|
|
} else {
|
|
inet_ntop(AF_INET, &in4->sin_addr, ip, sizeof(ip));
|
|
}
|
|
snprintf(sockname, sizeof(sockname), "%s:%d/%s", ip, ntohs(in4->sin_port), socktype==SOCK_STREAM?"tcp":"udp");
|
|
}
|
|
|
|
void CSocketAddress::BuildNameIpv6(void) {
|
|
char ip[64];
|
|
if(IN6_IS_ADDR_UNSPECIFIED(this->in6->sin6_addr.s6_addr32)) {
|
|
// wild address is ::
|
|
ip[0] = ':';
|
|
ip[1] = ':';
|
|
ip[2] = '\0';
|
|
} else {
|
|
inet_ntop(AF_INET6, &in6->sin6_addr, ip, sizeof(ip));
|
|
}
|
|
snprintf(sockname, sizeof(sockname), "%s:%d/%s", ip, ntohs(in6->sin6_port), socktype==SOCK_STREAM?"tcp":"udp");
|
|
}
|
|
|
|
void CSocketAddress::BuildNameBad(void)
|
|
{
|
|
snprintf(sockname, sizeof(sockname), "<BAD>");
|
|
}
|
|
|
|
void CSocketAddress::BuildName(void)
|
|
{
|
|
switch(addr->sa_family) {
|
|
case 0:
|
|
BuildNameNone();
|
|
break;
|
|
|
|
case AF_UNIX:
|
|
BuildNameUnix();
|
|
break;
|
|
|
|
case AF_INET:
|
|
BuildNameIpv4();
|
|
break;
|
|
|
|
case AF_INET6:
|
|
BuildNameIpv6();
|
|
break;
|
|
|
|
default:
|
|
BuildNameBad();
|
|
break;
|
|
}
|
|
}
|
|
|
|
const char * CSocketAddress::SetAddress(const char *name, int port, int type)
|
|
{
|
|
if(IsUnixSocketPath(name)) {
|
|
if(port != 0)
|
|
return "UNIX socket path hasnot a port";
|
|
return SetUnixAddress(name, type);
|
|
}
|
|
|
|
if(has2colon(name))
|
|
return SetIPv6Address(name, port, type);
|
|
|
|
if(name[0]=='*' || isdigit(name[0]))
|
|
return SetIPv4Address(name, port, type);
|
|
|
|
return SetHostAddress(name, port, type);
|
|
}
|
|
|
|
const char * CSocketAddress::SetAddress(const char *name, const char *portstr)
|
|
{
|
|
if(IsUnixSocketPath(name)) {
|
|
if(portstr != NULL && portstr[0] != '\0')
|
|
return "UNIX socket path hasnot a port";
|
|
return SetUnixAddress(name);
|
|
}
|
|
|
|
int port = 0;
|
|
int type = SOCK_STREAM;
|
|
if(portstr != NULL && portstr[0] != '\0') {
|
|
port = isdigit(portstr[0]) ? atoi(portstr) : name2port(portstr, SOCK_STREAM);
|
|
if(port==0)
|
|
return "Invalid TCP/UDP port";
|
|
const char *p = strrchr(portstr, '/');
|
|
if (p != NULL)
|
|
{
|
|
if(!strcmp(p+1, "udp")) {
|
|
type = SOCK_DGRAM;
|
|
} else if(!strcmp(p+1, "tcp")) {
|
|
type = SOCK_STREAM;
|
|
} else {
|
|
return "Invalid protocol name";
|
|
}
|
|
}
|
|
}
|
|
|
|
if(has2colon(name))
|
|
return SetIPv6Address(name, port, type);
|
|
|
|
if(name[0]=='*' || isdigit(name[0]))
|
|
return SetIPv4Address(name, port, type);
|
|
|
|
return SetHostAddress(name, port, type);
|
|
}
|
|
|
|
const char * CSocketAddress::SetAddress(const struct sockaddr_un *addr, int len, int type)
|
|
{
|
|
if(type != SOCK_STREAM && type != SOCK_DGRAM) {
|
|
return "Invalid protocol type\n";
|
|
}
|
|
socktype = type;
|
|
alen = len;
|
|
memcpy(un, addr, len);
|
|
BuildNameUnix();
|
|
return NULL;
|
|
}
|
|
|
|
const char * CSocketAddress::SetAddress(const struct sockaddr_in *addr, int len, int type) {
|
|
if(type != SOCK_STREAM && type != SOCK_DGRAM) {
|
|
return "Invalid protocol type\n";
|
|
}
|
|
if(len < (int)sizeof(struct sockaddr_in)) {
|
|
return "Invalid socklen\n";
|
|
}
|
|
socktype = type;
|
|
alen = sizeof(struct sockaddr_in);
|
|
*in4 = *addr;
|
|
BuildNameIpv4();
|
|
return NULL;
|
|
}
|
|
|
|
const char * CSocketAddress::SetAddress(const struct sockaddr_in6 *addr, int len, int type)
|
|
{
|
|
if(type != SOCK_STREAM && type != SOCK_DGRAM) {
|
|
return "Invalid protocol type\n";
|
|
}
|
|
if(len < (int)sizeof(struct sockaddr_in6)) {
|
|
return "Invalid socklen\n";
|
|
}
|
|
socktype = type;
|
|
alen = sizeof(struct sockaddr_in6);
|
|
*in6 = *addr;
|
|
BuildNameIpv6();
|
|
return NULL;
|
|
}
|
|
|
|
const char * CSocketAddress::SetAddress(const struct sockaddr *addr, int len, int type)
|
|
{
|
|
switch(addr->sa_family) {
|
|
case AF_UNIX: return SetAddress((const sockaddr_un *)addr, len, type);
|
|
case AF_INET: return SetAddress((const sockaddr_in *)addr, len, type);
|
|
case AF_INET6: return SetAddress((const sockaddr_in6 *)addr, len, type);
|
|
}
|
|
return "Unsupported socket family";
|
|
}
|
|
|
|
const char * CSocketAddress::SetUnixAddress(const char *name, int type)
|
|
{
|
|
int namelen = strlen(name);
|
|
if(namelen >= (int)sizeof(this->un->sun_path))
|
|
return "UNIX socket path name too long";
|
|
this->alen = InitUnixSocketAddress(this->un, name);
|
|
if(namelen >= 4 && !strcmp(name+namelen-4, "/udp"))
|
|
this->socktype = SOCK_DGRAM;
|
|
else if(namelen >= 4 && !strcmp(name+namelen-4, "-udp"))
|
|
this->socktype = SOCK_DGRAM;
|
|
else if(namelen >= 6 && !strcmp(name+namelen-6, "/dgram"))
|
|
this->socktype = SOCK_DGRAM;
|
|
else if(namelen >= 6 && !strcmp(name+namelen-6, "-dgram"))
|
|
this->socktype = SOCK_DGRAM;
|
|
else
|
|
this->socktype = type;
|
|
BuildNameUnix();
|
|
return NULL; // SUCC
|
|
}
|
|
|
|
const char * CSocketAddress::SetIPv4Address(const char *name, int port, int type)
|
|
{
|
|
const char *p = NULL;
|
|
|
|
if( (p = strchr(name, '/')) != NULL)
|
|
{
|
|
p++;
|
|
if(!strcmp(p, "udp"))
|
|
type = SOCK_DGRAM;
|
|
else if(!strcmp(p, "tcp"))
|
|
type = SOCK_STREAM;
|
|
else
|
|
return "Unknown IPv4 protocol";
|
|
}
|
|
|
|
if( (p = strrchr(name, ':')) != NULL)
|
|
{
|
|
p++;
|
|
if(strchr(p, '.'))
|
|
return "Invalid TCP/UDP port";
|
|
port = isdigit(p[0]) ? atoi(p) : name2port(p, type);
|
|
if(port==0)
|
|
return "Invalid TCP/UDP port";
|
|
}
|
|
|
|
if(port == 0)
|
|
port = 8888;
|
|
else if(port < 0 || port >= 65536)
|
|
return "TCP/UDP port must between 1-65535";
|
|
|
|
unsigned int ipv4 = ip2addr(name);
|
|
if(ipv4 == INADDR_NONE)
|
|
return "Invalid IPv4 address";
|
|
|
|
socktype = type;
|
|
alen = sizeof(struct sockaddr_in);
|
|
memset(in4, 0, alen);
|
|
in4->sin_family = AF_INET;
|
|
in4->sin_addr.s_addr = ipv4;
|
|
in4->sin_port = htons(port);
|
|
BuildNameIpv4();
|
|
return NULL;
|
|
}
|
|
|
|
const char * CSocketAddress::SetIPv6Address(const char *name, int port, int type)
|
|
{
|
|
const char *p = NULL;
|
|
|
|
if( (p = strchr(name, '/')) != NULL )
|
|
{
|
|
p++;
|
|
if(!strcmp(p, "udp"))
|
|
type = SOCK_DGRAM;
|
|
else if(!strcmp(p, "tcp"))
|
|
type = SOCK_STREAM;
|
|
else
|
|
return "Unknown IPv6 protocol";
|
|
}
|
|
|
|
if(port == 0)
|
|
{
|
|
// always has 2 colon, seek to right most colon
|
|
p = strrchr(name, ':') + 1;
|
|
if(strchr(p, '.'))
|
|
return "Invalid TCP/UDP port";
|
|
port = isdigit(p[0]) ? atoi(p) : name2port(p, type);
|
|
if(port==0)
|
|
return "Invalid TCP/UDP port";
|
|
}
|
|
|
|
if(port == 0)
|
|
port = 8888;
|
|
else if(port < 0 || port >= 65536)
|
|
return "TCP/UDP port must between 1-65535";
|
|
|
|
char addr[16];
|
|
// IPv6 has not '*', use '::' instead
|
|
|
|
if(p) {
|
|
// p pointer to : or /
|
|
|
|
// make a new copy of name, strip last colon
|
|
// colon is a valid seperator in IPv6 numeric address
|
|
int len = p - name;
|
|
char localname[len];
|
|
memcpy(localname, name, len);
|
|
localname[len-1] = 0;
|
|
if(inet_pton(AF_INET6, localname, &addr) <= 0)
|
|
return "Invalid IPv6 address";
|
|
} else {
|
|
if(inet_pton(AF_INET6, name, &addr) <= 0)
|
|
return "Invalid IPv6 address";
|
|
}
|
|
|
|
socktype = type;
|
|
alen = sizeof(struct sockaddr_in6);
|
|
memset(in6, 0, alen);
|
|
in6->sin6_family = AF_INET6;
|
|
memcpy(in6->sin6_addr.s6_addr, addr, 16);
|
|
in6->sin6_port = htons(port);
|
|
BuildNameIpv6();
|
|
return NULL;
|
|
}
|
|
|
|
const char * CSocketAddress::SetHostAddress(const char *name, int port, int type)
|
|
{
|
|
const char *p;
|
|
|
|
if( (p = strchr(name, '/')) != NULL)
|
|
{
|
|
p++;
|
|
if(!strcmp(p, "udp"))
|
|
type = SOCK_DGRAM;
|
|
else if(!strcmp(p, "tcp"))
|
|
type = SOCK_STREAM;
|
|
else
|
|
return "Unknown IPv4/IPv6 protocol";
|
|
}
|
|
|
|
if( (p = strrchr(name, ':')) != NULL)
|
|
{
|
|
p++;
|
|
if(strchr(p, '.'))
|
|
return "Invalid TCP/UDP port";
|
|
port = isdigit(p[0]) ? atoi(p) : name2port(p, type);
|
|
if(port==0)
|
|
return "Invalid TCP/UDP port";
|
|
}
|
|
|
|
if(port == 0)
|
|
port = 8888;
|
|
else if(port < 0 || port >= 65536)
|
|
return "TCP/UDP port must between 1-65535";
|
|
|
|
// p pointer to start of port
|
|
if(p==NULL)
|
|
p = strchr(name, '/');
|
|
|
|
uint32_t addr[4];
|
|
int family = 0;
|
|
// or if port missing, start of protocol
|
|
if(p==NULL)
|
|
{
|
|
family = name2addr(name, addr);
|
|
} else {
|
|
int len = p - name;
|
|
char localname[len];
|
|
memcpy(localname, name, len);
|
|
localname[len-1] = 0;
|
|
family = name2addr(localname, addr);
|
|
}
|
|
|
|
switch(family) {
|
|
default:
|
|
return "Invalid Hostname";
|
|
|
|
case AF_INET:
|
|
socktype = type;
|
|
alen = sizeof(struct sockaddr_in);
|
|
memset(in4, 0, alen);
|
|
in4->sin_family = AF_INET;
|
|
in4->sin_addr.s_addr = addr[0];
|
|
in4->sin_port = htons(port);
|
|
BuildNameIpv4();
|
|
break;
|
|
|
|
case AF_INET6:
|
|
socktype = type;
|
|
alen = sizeof(struct sockaddr_in6);
|
|
memset(in6, 0, alen);
|
|
in6->sin6_family = AF_INET6;
|
|
memcpy(in6->sin6_addr.s6_addr, addr, 16);
|
|
in6->sin6_port = htons(port);
|
|
BuildNameIpv6();
|
|
};
|
|
return NULL;
|
|
}
|
|
|
|
// Match().... return 1 if address is identical
|
|
int CSocketAddress::Equal(const sockaddr *that, int alen, int type) const
|
|
{
|
|
if( this->socktype != type ) return 0;
|
|
if( this->addr->sa_family != that->sa_family) return 0;
|
|
|
|
switch(this->addr->sa_family) {
|
|
case AF_UNIX:
|
|
{
|
|
const struct sockaddr_un *un = (const struct sockaddr_un *)that;
|
|
if( this->un->sun_path[0] != un->sun_path[0]) {
|
|
return 0;
|
|
}
|
|
if( this->un->sun_path[0] == '/' && un->sun_path[0] == '/') {
|
|
if(!strncmp(this->un->sun_path, un->sun_path, sizeof(un->sun_path))) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AF_INET:
|
|
{
|
|
const struct sockaddr_in *in4 = (const struct sockaddr_in *)that;
|
|
return alen >= (int)sizeof(struct sockaddr_in) &&
|
|
this->in4->sin_port == in4->sin_port &&
|
|
this->in4->sin_addr.s_addr == in4->sin_addr.s_addr;
|
|
}
|
|
break;
|
|
|
|
case AF_INET6:
|
|
if(alen < (int)sizeof(struct sockaddr_in6))
|
|
return 0;
|
|
|
|
{
|
|
const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)that;
|
|
if( this->in6->sin6_port != in6->sin6_port )
|
|
return 0;
|
|
|
|
if(!IN6_ARE_ADDR_EQUAL(this->in6->sin6_addr.s6_addr32, in6->sin6_addr.s6_addr32))
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
break;
|
|
};
|
|
|
|
if( (int)this->alen != alen ) return 0;
|
|
return !memcmp(&this->addr, addr, alen);
|
|
}
|
|
|
|
int CSocketAddress::Equal(const CSocketAddress *that) const
|
|
{
|
|
return Equal(that->addr, that->alen, that->socktype);
|
|
}
|
|
|
|
int CSocketAddress::Equal(const struct sockaddr_un *addr, int len, int type) const
|
|
{
|
|
return Equal((const struct sockaddr *)addr, len, type);
|
|
}
|
|
int CSocketAddress::Equal(const struct sockaddr_in *addr, int len, int type) const
|
|
{
|
|
return Equal((const struct sockaddr *)addr, len, type);
|
|
}
|
|
int CSocketAddress::Equal(const struct sockaddr_in6 *addr, int len, int type) const
|
|
{
|
|
return Equal((const struct sockaddr *)addr, len, type);
|
|
}
|
|
|
|
int CSocketAddress::Equal(const char *path) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(path, 0) < 0)
|
|
return 0;
|
|
return Equal(&temp);
|
|
}
|
|
|
|
int CSocketAddress::Equal(const char *path, int port, int type) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(path, port, type) < 0)
|
|
return 0;
|
|
return Equal(&temp);
|
|
}
|
|
int CSocketAddress::Equal(const char *path, const char * port) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(path, port) < 0)
|
|
return 0;
|
|
return Equal(&temp);
|
|
}
|
|
|
|
// Match().... return wether this object accept the peer address
|
|
int CSocketAddress::Match(const CSocketAddress *that) const
|
|
{
|
|
if( this->socktype != that->socktype ) return 0;
|
|
|
|
int this_family = this->addr->sa_family;
|
|
uint32_t this_ipv4 = INADDR_NONE;
|
|
uint16_t this_port = 0;
|
|
uint32_t that_ipv4 = INADDR_NONE;
|
|
uint16_t that_port = 0;
|
|
|
|
// cast down V4MAPPED to ipv4
|
|
switch(this_family) {
|
|
case AF_INET:
|
|
this_ipv4 = this->in4->sin_addr.s_addr;
|
|
this_port = this->in4->sin_port;
|
|
break;
|
|
case AF_INET6:
|
|
if(IN6_IS_ADDR_V4MAPPED(this->in6->sin6_addr.s6_addr32)) {
|
|
this_family = AF_INET;
|
|
this_ipv4 = this->in6->sin6_addr.s6_addr[3];
|
|
this_port = this->in6->sin6_port;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// cast down V4MAPPED to ipv4
|
|
switch(that->addr->sa_family) {
|
|
case AF_INET:
|
|
that_ipv4 = that->in4->sin_addr.s_addr;
|
|
that_port = that->in4->sin_port;
|
|
break;
|
|
case AF_INET6:
|
|
if(IN6_IS_ADDR_V4MAPPED(that->in6->sin6_addr.s6_addr32)) {
|
|
that_ipv4 = that->in6->sin6_addr.s6_addr[3];
|
|
that_port = that->in6->sin6_port;
|
|
}
|
|
if(IN6_IS_ADDR_UNSPECIFIED(that->in6->sin6_addr.s6_addr32)) {
|
|
that_ipv4 = INADDR_ANY;
|
|
that_port = that->in6->sin6_port;
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch(this_family) {
|
|
case AF_UNIX:
|
|
if( this->un->sun_path[0] != that->un->sun_path[0]) {
|
|
return 0;
|
|
}
|
|
if( this->un->sun_path[0] == '/' && that->un->sun_path[0] == '/') {
|
|
if(!strncmp(this->un->sun_path, that->un->sun_path, sizeof(that->un->sun_path))) {
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AF_INET:
|
|
if( this_port != that_port )
|
|
return 0;
|
|
|
|
if( this_ipv4 == that_ipv4 )
|
|
return 1;
|
|
|
|
// * any address
|
|
if( this_ipv4 == INADDR_ANY ) {
|
|
if( is_local_ipv4(that_ipv4) )
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
break;
|
|
|
|
case AF_INET6:
|
|
// :: zero address
|
|
this_port = this->in6->sin6_port;
|
|
|
|
if(IN6_IS_ADDR_UNSPECIFIED(this->in6->sin6_addr.s6_addr32))
|
|
{
|
|
if( is_local_ipv4(that_ipv4) && this_port == that_port )
|
|
return 1;
|
|
|
|
if(that->addr->sa_family==AF_INET6 && this_port == that->in6->sin6_port) {
|
|
if(IN6_IS_ADDR_UNSPECIFIED(that->in6->sin6_addr.s6_addr32))
|
|
return 1;
|
|
if(IN6_IS_ADDR_LOOPBACK(that->in6->sin6_addr.s6_addr32))
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if( that->addr->sa_family==AF_INET6 ) {
|
|
if(this_port != that->in6->sin6_port)
|
|
return 0;
|
|
if(IN6_ARE_ADDR_EQUAL(this->in6->sin6_addr.s6_addr32, that->in6->sin6_addr.s6_addr32))
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
break;
|
|
};
|
|
if( this->alen != that->alen ) return 0;
|
|
return !memcmp(&this->addr, &that->addr, this->alen);
|
|
}
|
|
|
|
int CSocketAddress::Match(const char *path, int port, int type) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(path, port, type) < 0)
|
|
return 0;
|
|
return Match(&temp);
|
|
}
|
|
|
|
int CSocketAddress::Match(const char *path) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(path, 0) < 0)
|
|
return 0;
|
|
return Match(&temp);
|
|
}
|
|
|
|
int CSocketAddress::Match(const char *path, const char * port) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(path, port) < 0)
|
|
return 0;
|
|
return Match(&temp);
|
|
}
|
|
|
|
int CSocketAddress::Match(const struct sockaddr_un *addr, int len, int type) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(addr, len, type) < 0)
|
|
return 0;
|
|
return Match(&temp);
|
|
}
|
|
int CSocketAddress::Match(const struct sockaddr_in *addr, int len, int type) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(addr, len, type) < 0)
|
|
return 0;
|
|
return Match(&temp);
|
|
}
|
|
|
|
int CSocketAddress::Match(const struct sockaddr_in6 *addr, int len, int type) const
|
|
{
|
|
CSocketAddress temp;
|
|
if(temp.SetAddress(addr, len, type) < 0)
|
|
return 0;
|
|
return Match(&temp);
|
|
}
|
|
|