#ifndef __ip6_h
#define __ip6_h
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include "mem.h"
#include "str.h"
#ifndef IP_LEN
#define IP_LEN 16
#endif
static int inline ipv6_null(unsigned char *ip)
{
int i;
for (i = 0; ip[i] == 0 && i < 16; i++);
return i == 16 ? 1 : 0;
}
static int inline ipv6_helper(const char *str, unsigned char ip[16], unsigned char *sub)
{
register int p, v, v4, v6, n;
int x[8];
int c, s, d, saw_colon;
/* and you thought ipv4 was bad... */
saw_colon = 0;
for (p = s = d = v4 = v6 = n = 0, c = -1; p < 8 && *str; str++) {
switch (*str) {
case '0': v = 0; break;
case '1': v = 1; break;
case '2': v = 2; break;
case '3': v = 3; break;
case '4': v = 4; break;
case '5': v = 5; break;
case '6': v = 6; break;
case '7': v = 7; break;
case '8': v = 8; break;
case '9': v = 9; break;
case 'a': case 'A': v = 10; break;
case 'b': case 'B': v = 11; break;
case 'c': case 'C': v = 12; break;
case 'd': case 'D': v = 13; break;
case 'e': case 'E': v = 14; break;
case 'f': case 'F': v = 15; break;
case '/':
/* cidr */
if (!sub) return 0;
s = 1;
if (d) {
x[p] = v4;
} else {
x[p] = v6;
}
p++; v4 = v6 = n = 0;
break;
case ':':
if (s || d) return 0;
saw_colon = 1;
x[p] = v6; p++; v4 = v6 = n = 0;
if (str[1] == ':') {
c = p;
str++;
}
break;
case '.':
if (s) return 0;
x[p] = v4; p++; v4 = v6 = n = 0;
d = 1;
break;
default:
return 0;
};
v4 *= 10; v4 += v;
v6 *= 16; v6 += v;
n++;
}
if (!saw_colon) {
/* could be ipv4... */
return 0;
}
if (n) {
if (s) {
if (!sub) return 0;
/* last atom was subnet */
if (v4 < 0 || v4 > 128) return 0;
/* invert */
v4 = 128 - v4;
for (v6 = v = 0; v6 < 16; v += 8, v6++) {
if (v4 < v) {
sub[v6] = (0xFF << v4) & 0xFF;
} else {
sub[v6] = 0xFF;
}
}
} else if (d) {
x[p] = v4;
p++;
} else {
x[p] = v6;
p++;
}
}
for (v = v4 = 0; v < c; v++, v4++, v4++) {
ip[v4] = (x[v] & 0xFF00) >> 8;
ip[v4+1] = (x[v] & 0x00FF);
}
v6 = (16 - p) + v4;
if (!sub && v6 != 0 && c == -1)
return 0;
for (; v4 < v6; v4++)
ip[v4] = 0;
for (v = (c == -1 ? 0 : c); v < p; v++, v4++, v4++) {
ip[v4] = (x[v] & 0xFF00) >> 8;
ip[v4+1] = (x[v] & 0x00FF);
}
for (; v4 < 32; v4++) {
ip[v4] = 0; /* set the rest of the bits to 0 */
}
return 1;
}
static int inline ipv6_scan(const char *str, unsigned char ip[16])
{
return ipv6_helper(str, ip, 0) ? 16 : 0;
}
static int inline ipv6_cidr(const char *str, unsigned char ip[32])
{
return ipv6_helper(str, ip, ip+16) ? 32 : 0;
}
static int inline ipv6_in_subnet(unsigned char cidr[32], unsigned char ip[16])
{
register int i;
for (i = 0; i < 16 && cidr[i] == 0; i++);
if (i == 16) return 1;
for (i = 0; i < 16; i++) {
if (cidr[i] != (ip[i] & cidr[16+i]))
return 0;
}
return 1;
}
static int inline socket_bind6(int fd, unsigned char ip[16], int port)
{
struct sockaddr_in6 sin;
memzero(&sin, sizeof(sin));
sin.sin6_family = PF_INET6;
sin.sin6_port = htons(port);
memcpy(&sin.sin6_addr, ip, 16);
return bind(fd, (struct sockaddr *)&sin, sizeof(sin));
}
static int inline socket_bind6_reuse(int fd, unsigned char ip[16], int port)
{
int opt = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
return socket_bind6(fd, ip, port);
}
static int inline socket_peer6(int fd, unsigned char ip[16], int *port)
{
struct sockaddr_in6 sin;
int silen;
memzero(&sin, sizeof(sin));
silen = sizeof(sin);
sin.sin6_family = PF_INET6;
if (getpeername(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) {
return 0;
}
if (sin.sin6_family != PF_INET6)
return 0;
/* Clib */
memcpy(ip, &sin.sin6_addr, 16);
*port = ntohs(sin.sin6_port);
return 1;
}
static int inline socket_local6(int fd, unsigned char ip[16], int *port)
{
struct sockaddr_in6 sin;
int silen;
memzero(&sin, sizeof(sin));
silen = sizeof(sin);
sin.sin6_family = PF_INET6;
if (getsockname(fd, (struct sockaddr *)&sin, (int *)&silen) == -1) {
return 0;
}
if (sin.sin6_family != PF_INET6)
return 0;
/* Clib */
memcpy(ip, &sin.sin6_addr, 16);
*port = ntohs(sin.sin6_port);
return 1;
}
static int inline socket_tcp6(void)
{
int fd;
fd = socket(PF_INET6, SOCK_STREAM, 0);
if (fd == -1) return -1;
if (ndelay_on(fd) == -1) { close(fd); return -1; }
return fd;
}
static int inline socket_udp6(void)
{
int fd;
fd = socket(PF_INET6, SOCK_DGRAM, 0);
if (fd == -1) return -1;
if (ndelay_on(fd) == -1) { close(fd); return -1; }
return fd;
}
static int inline socket_accept6(int s, unsigned char ip[16], int *port)
{
struct sockaddr_in6 sa;
int dummy = sizeof sa;
int r;
memzero(&sa, sizeof(sa));
r = accept(s, (struct sockaddr *)&sa, &dummy);
if (r == -1) return -1;
/* Clib */
memcpy(ip, &sa.sin6_addr, 16);
*port = ntohs(sa.sin6_port);
return r;
}
static int inline socket_recv6(int s, char *buf, int len, unsigned char ip[16], int *port)
{
struct sockaddr_in6 sa;
int dummy = sizeof sa;
int r;
memzero(&sa, sizeof(sa));
r = recvfrom(s, buf, len, 0, (struct sockaddr *)&sa, &dummy);
if (r == -1) return -1;
/* Clib */
memcpy(ip, &sa.sin6_addr, 16);
*port = ntohs(sa.sin6_port);
return r;
}
static int inline socket_send6(int s, const char *buf, int len, const unsigned char ip[16], int port)
{
struct sockaddr_in6 sa;
memzero(&sa, sizeof(sa));
sa.sin6_family = PF_INET6;
/* Clib */
sa.sin6_port = htons(port);
memcpy(&sa.sin6_addr, ip, 16);
return sendto(s, buf, len, 0, (struct sockaddr *)&sa, sizeof(sa));
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1