summaryrefslogtreecommitdiffstats
path: root/rfc1035/rfc1035an.c
blob: 7459530340e7e0229b17a6ba8bd66d0ecdfaf0c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#include	"config.h"
#include	"rfc1035.h"
#include	<sys/types.h>
#include	<sys/socket.h>
#include	<arpa/inet.h>
#include	<errno.h>
#include	<string.h>


void rfc1035_ntoa_ipv4(const struct in_addr *in, char *buf)
{
union	{
	unsigned char addr[4];
	RFC1035_UINT32 n;
	} u;

int	i;
char	*p;
char	pbuf[4];

	u.n=in->s_addr;
	for (i=0; i<4; i++)
	{
		if (i)	*buf++='.';
		p=pbuf+3;
		*p=0;
		do
		{
			*--p = '0' + (u.addr[i] % 10);
		} while ( (u.addr[i] /= 10) != 0);
		while (*p)
			*buf++ = *p++;
	}
	*buf=0;
}

void rfc1035_ntoa(const RFC1035_ADDR *in, char *buf)
{
#if	RFC1035_IPV6
	inet_ntop(AF_INET6, in, buf, RFC1035_MAXNAMESIZE+1);
#else
	rfc1035_ntoa_ipv4(in, buf);
#endif
}

static RFC1035_UINT32 doaton(const char *p, int *err)
{
RFC1035_UINT32 octets[4];
int	i;
int	base;

	*err=1;
	for (i=0; i<4; i++)
	{
		if (i > 0)
		{
			if (*p == '\0')	break;
			if (*p != '.')	return ( -1 );
			++p;
		}
		if (*p < '0' || *p > '9')	return (-1);
		octets[i]=0;
		base=10;
		if (*p == '0')	base=8;

		while (*p >= '0' && *p < '0'+base)
			octets[i] = octets[i] * base + (*p++ - '0');
	}
	if (*p)	return ( -1 );
	*err=0;
	if (i == 1)	return (octets[0]);
	*err=1;
	if (octets[0] > 255)	return ( -1 );
	octets[0] <<= 24;

	if (i == 2)
	{
		if (octets[1] > 0x00FFFFFF)	return ( -1 );
		*err=0;
		return (octets[0] | octets[1]);
	}

	if (octets[1] > 255)	return ( -1 );
	octets[1] <<= 16;
	if (i == 3)
	{
		if (octets[2] > 0x0000FFFF)	return ( -1 );
		*err=0;
		return (octets[0] | octets[1] | octets[2]);
	}
	if (octets[2] > 255 || octets[3] > 255)	return ( -1 );
	*err=0;
	return (octets[0] | octets[1] | (octets[2] << 8) | octets[3]);
}

int rfc1035_aton_ipv4(const char *p, struct in_addr *in4)
{
int	dummy;
RFC1035_UINT32 n=doaton(p, &dummy);
union	{
	unsigned char addr[4];
	struct in_addr n;
	} u;

	u.addr[3]=n;
	u.addr[2]=n >> 8;
	u.addr[1]=n >> 16;
	u.addr[0]=n >> 24;

	if (dummy)	errno=EINVAL;
	*in4=u.n;
	return (dummy);
}

#if	RFC1035_IPV6

int rfc1035_aton(const char *p, RFC1035_ADDR *in6)
{
struct in_addr	in4;

	if (rfc1035_aton_ipv4(p, &in4) == 0)
	{
		rfc1035_ipv4to6(in6, &in4);
		return (0);
	}
	if (inet_pton(AF_INET6, p, in6) <= 0)
		return (-1);
	return (0);
}

#else

int rfc1035_aton(const char *p, RFC1035_ADDR *in4)
{
	return (rfc1035_aton_ipv4(p, in4));
}
#endif