]> arthur.barton.de Git - ngircd-alex.git/blob - src/ipaddr/ng_ipaddr.c
af524d091fa569dd874559a3f032f5dcc0cfde6d
[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
29         assert(ip_str);
30
31         memset(&hints, 0, sizeof(hints));
32         hints.ai_flags = AI_NUMERICHOST;
33 #ifndef WANT_IPV6       /* do not convert ipv6 addresses */
34         hints.ai_family = AF_INET;
35 #endif
36
37         /* some getaddrinfo implementations require that ai_socktype is set. */
38         hints.ai_socktype = SOCK_STREAM;
39
40         /* silly, but ngircd stores UINT16 in server config, not string */
41         snprintf(portstr, sizeof(portstr), "%u", (unsigned int) port);
42
43         ret = getaddrinfo(ip_str, portstr, &hints, &res0);
44         if (ret != 0)
45                 return false;
46
47         assert(sizeof(*addr) >= res0->ai_addrlen);
48         if (sizeof(*addr) >= res0->ai_addrlen)
49                 memcpy(addr, res0->ai_addr, res0->ai_addrlen);
50         else
51                 ret = -1;
52         freeaddrinfo(res0);
53         return ret == 0;
54 #else /* HAVE_GETADDRINFO */
55         assert(ip_str);
56         memset(addr, 0, sizeof *addr);
57 #ifdef HAVE_sockaddr_in_len
58         addr->sin4.sin_len = sizeof(addr->sin4);
59 #endif
60         addr->sin4.sin_family = AF_INET;
61 # ifdef HAVE_INET_ATON
62         if (inet_aton(ip_str, &addr->sin4.sin_addr) == 0)
63                 return false;
64 # else
65         addr->sin4.sin_addr.s_addr = inet_addr(ip_str);
66         if (addr->sin4.sin_addr.s_addr == (unsigned) -1)
67                 return false;
68 # endif
69         ng_ipaddr_setport(addr, port);
70         return true;
71 #endif /* HAVE_GETADDRINFO */
72 }
73
74
75 GLOBAL void
76 ng_ipaddr_setport(ng_ipaddr_t *a, UINT16 port)
77 {
78 #ifdef WANT_IPV6
79         int af;
80
81         assert(a != NULL);
82
83         af = a->sa.sa_family;
84
85         assert(af == AF_INET || af == AF_INET6);
86
87         switch (af) {
88         case AF_INET:
89                 a->sin4.sin_port = htons(port);
90                 break;
91         case AF_INET6:
92                 a->sin6.sin6_port = htons(port);
93                 break;
94         }
95 #else /* WANT_IPV6 */
96         assert(a != NULL);
97         assert(a->sin4.sin_family == AF_INET);
98         a->sin4.sin_port = htons(port);
99 #endif /* WANT_IPV6 */
100 }
101
102
103
104 GLOBAL bool
105 ng_ipaddr_ipequal(const ng_ipaddr_t *a, const ng_ipaddr_t *b)
106 {
107         assert(a != NULL);
108         assert(b != NULL);
109 #ifdef WANT_IPV6
110         if (a->sa.sa_family != b->sa.sa_family)
111                 return false;
112         assert(ng_ipaddr_salen(a) == ng_ipaddr_salen(b));
113         switch (a->sa.sa_family) {
114         case AF_INET6:
115                 return IN6_ARE_ADDR_EQUAL(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
116         case AF_INET:
117                 return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
118         }
119         return false;
120 #else
121         assert(a->sin4.sin_family == AF_INET);
122         assert(b->sin4.sin_family == AF_INET);
123         return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
124 #endif
125 }
126
127
128 #ifdef WANT_IPV6
129 GLOBAL const char *
130 ng_ipaddr_tostr(const ng_ipaddr_t *addr)
131 {
132         static char strbuf[NG_INET_ADDRSTRLEN];
133
134         strbuf[0] = 0;
135
136         ng_ipaddr_tostr_r(addr, strbuf);
137         return strbuf;
138 }
139
140
141 /* str must be at least NG_INET_ADDRSTRLEN bytes long */
142 GLOBAL bool
143 ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *str)
144 {
145 #ifdef HAVE_GETNAMEINFO
146         const struct sockaddr *sa = (const struct sockaddr *) addr;
147         int ret;
148
149         *str = 0;
150
151         ret = getnameinfo(sa, ng_ipaddr_salen(addr),
152                         str, NG_INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
153         /*
154          * avoid leading ':'.
155          * causes mis-interpretation of client host in e.g. /WHOIS
156          */
157         if (*str == ':') {
158                 char tmp[NG_INET_ADDRSTRLEN] = "0";
159                 ret = getnameinfo(sa, ng_ipaddr_salen(addr),
160                                   tmp + 1, (socklen_t)sizeof(tmp) - 1,
161                                   NULL, 0, NI_NUMERICHOST);
162                 if (ret == 0)
163                         strlcpy(str, tmp, NG_INET_ADDRSTRLEN);
164         }
165         assert (ret == 0);
166         return ret == 0;
167 #else
168         abort(); /* WANT_IPV6 depends on HAVE_GETNAMEINFO */
169 #endif
170 }
171
172 #endif /* WANT_IPV6 */
173
174 /* -eof- */