]> arthur.barton.de Git - ngircd-alex.git/blob - src/ipaddr/ng_ipaddr.c
3b0595d79719b92b13edfd0f4a5422311f1ff550
[ngircd-alex.git] / src / ipaddr / ng_ipaddr.c
1 /*
2  * Functions for AF_ agnostic ipv4/ipv6 handling.
3  *
4  * (c) 2008 Florian Westphal <fw@strlen.de>, public domain.
5  */
6
7 #include "portab.h"
8
9 #include <assert.h>
10 #include <stdio.h>
11 #include <string.h>
12
13 #ifdef HAVE_GETADDRINFO
14 #include <netdb.h>
15 #include <sys/types.h>
16 #endif
17
18 #include "ng_ipaddr.h"
19
20 GLOBAL bool
21 ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port)
22 {
23 #ifdef HAVE_GETADDRINFO
24         int ret;
25         char portstr[64];
26         struct addrinfo *res0;
27         struct addrinfo hints = {
28 #ifndef WANT_IPV6       /* only accept v4 addresses */
29                 .ai_family = AF_INET,
30 #endif
31                 .ai_flags = AI_NUMERICHOST
32         };
33
34         if (ip_str == NULL)
35                 hints.ai_flags |= AI_PASSIVE;
36
37         /* silly, but ngircd stores UINT16 in server config, not string */
38         snprintf(portstr, sizeof(portstr), "%u", (unsigned int) port);
39         ret = getaddrinfo(ip_str, portstr, &hints, &res0);
40         assert(ret == 0);
41         if (ret != 0)
42                 return false;
43
44         assert(sizeof(*addr) >= res0->ai_addrlen);
45         if (sizeof(*addr) >= res0->ai_addrlen)
46                 memcpy(addr, res0->ai_addr, res0->ai_addrlen);
47         else
48                 ret = -1;
49         freeaddrinfo(res0);
50         return ret == 0;
51 #else /* HAVE_GETADDRINFO */
52         if (ip_str == NULL)
53                 ip_str = "0.0.0.0";
54         addr->sin4.sin_family = AF_INET;
55 # ifdef HAVE_INET_ATON
56         if (inet_aton(ip_str, &addr->sin4.sin_addr) == 0)
57                 return false;
58 # else
59         addr->sin4.sin_addr.s_addr = inet_addr(ip_str);
60         if (addr->sin4.sin_addr.s_addr == (unsigned) -1)
61                 return false;
62 # endif
63         ng_ipaddr_setport(addr, port);
64         return true;
65 #endif /* HAVE_GETADDRINFO */
66 }
67
68
69 GLOBAL void
70 ng_ipaddr_setport(ng_ipaddr_t *a, UINT16 port)
71 {
72 #ifdef WANT_IPV6
73         int af;
74
75         assert(a != NULL);
76
77         af = a->sa.sa_family;
78
79         assert(af == AF_INET || af == AF_INET6);
80
81         switch (af) {
82         case AF_INET:
83                 a->sin4.sin_port = htons(port);
84                 break;
85         case AF_INET6:
86                 a->sin6.sin6_port = htons(port);
87                 break;
88         }
89 #else /* WANT_IPV6 */
90         assert(a != NULL);
91         assert(a->sin4.sin_family == AF_INET);
92         a->sin4.sin_port = htons(port);
93 #endif /* WANT_IPV6 */
94 }
95
96
97
98 GLOBAL bool
99 ng_ipaddr_ipequal(const ng_ipaddr_t *a, const ng_ipaddr_t *b)
100 {
101         assert(a != NULL);
102         assert(b != NULL);
103 #ifdef WANT_IPV6
104         if (a->sa.sa_family != b->sa.sa_family)
105                 return false;
106         assert(ng_ipaddr_salen(a) == ng_ipaddr_salen(b));
107         switch (a->sa.sa_family) {
108         case AF_INET6:
109                 return IN6_ARE_ADDR_EQUAL(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
110         case AF_INET:
111                 return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
112         }
113         return false;
114 #else
115         assert(a->sin4.sin_family == AF_INET);
116         assert(b->sin4.sin_family == AF_INET);
117         return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
118 #endif
119 }
120
121
122 #ifdef WANT_IPV6
123 GLOBAL const char *
124 ng_ipaddr_tostr(const ng_ipaddr_t *addr)
125 {
126         static char strbuf[NG_INET_ADDRSTRLEN];
127
128         strbuf[0] = 0;
129
130         ng_ipaddr_tostr_r(addr, strbuf);
131         return strbuf;
132 }
133
134
135 /* str must be at least NG_INET_ADDRSTRLEN bytes long */
136 GLOBAL bool
137 ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *str)
138 {
139 #ifdef HAVE_GETNAMEINFO
140         const struct sockaddr *sa = (const struct sockaddr *) addr;
141         int ret;
142
143         *str = 0;
144
145         ret = getnameinfo(sa, ng_ipaddr_salen(addr),
146                         str, NG_INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
147         /*
148          * avoid leading ':'.
149          * causes mis-interpretation of client host in e.g. /WHOIS
150          */
151         if (*str == ':') {
152                 char tmp[NG_INET_ADDRSTRLEN] = "0";
153                 ret = getnameinfo(sa, ng_ipaddr_salen(addr),
154                                 tmp+1, sizeof(tmp) -1, NULL, 0, NI_NUMERICHOST);
155                 if (ret == 0)
156                         strlcpy(str, tmp, NG_INET_ADDRSTRLEN);
157         }
158         assert (ret == 0);
159         return ret == 0;
160 #else
161         abort(); /* WANT_IPV6 depends on HAVE_GETNAMEINFO */
162 #endif
163 }
164
165 #endif /* WANT_IPV6 */
166
167 /* -eof- */