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