2 * Copyright (C) 2001 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 /* ipv4 and ipv6 networking functions with a common interface */
32 #define NETWORK_PRIVATE
35 #define RAND_INT(n) ((int)(rand() / (RAND_MAX + 1.0) * (n)))
38 /* ================== COMMON ================= */
41 net_set_socket_options (int sok
)
46 setsockopt (sok
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &sw
, sizeof (sw
));
48 setsockopt (sok
, SOL_SOCKET
, SO_KEEPALIVE
, (char *) &sw
, sizeof (sw
));
56 ia
.s_addr
= htonl (addr
);
57 return inet_ntoa (ia
);
61 net_store_destroy (netstore
* ns
)
65 freeaddrinfo (ns
->ip6_hostent
);
75 ns
= malloc (sizeof (netstore
));
76 memset (ns
, 0, sizeof (netstore
));
83 /* =================== IPV4 ================== */
86 A note about net_resolve and lookupd:
88 Many IRC networks rely on round-robin DNS for load balancing, rotating the list
89 of IP address on each query. However, this method breaks when DNS queries are
90 cached. Mac OS X and Darwin handle DNS lookups through the lookupd daemon, which
91 caches queries in its default configuration: thus, if we always pick the first
92 address, we will be stuck with the same host (which might be down!) until the
93 TTL reaches 0 or lookupd is reset (typically, at reboot). Therefore, we need to
94 pick a random address from the result list, instead of always using the first.
98 net_resolve (netstore
* ns
, char *hostname
, int port
, char **real_host
)
100 ns
->ip4_hostent
= gethostbyname (hostname
);
101 if (!ns
->ip4_hostent
)
104 memset (&ns
->addr
, 0, sizeof (ns
->addr
));
107 while (ns
->ip4_hostent
->h_addr_list
[count
]) count
++;
108 memcpy (&ns
->addr
.sin_addr
,
109 ns
->ip4_hostent
->h_addr_list
[RAND_INT(count
)],
110 ns
->ip4_hostent
->h_length
);
112 memcpy (&ns
->addr
.sin_addr
, ns
->ip4_hostent
->h_addr
,
113 ns
->ip4_hostent
->h_length
);
115 ns
->addr
.sin_port
= htons (port
);
116 ns
->addr
.sin_family
= AF_INET
;
118 *real_host
= strdup (ns
->ip4_hostent
->h_name
);
119 return strdup (inet_ntoa (ns
->addr
.sin_addr
));
123 net_connect (netstore
* ns
, int sok4
, int sok6
, int *sok_return
)
126 return connect (sok4
, (struct sockaddr
*) &ns
->addr
, sizeof (ns
->addr
));
130 net_bind (netstore
* tobindto
, int sok4
, int sok6
)
132 bind (sok4
, (struct sockaddr
*) &tobindto
->addr
, sizeof (tobindto
->addr
));
136 net_sockets (int *sok4
, int *sok6
)
138 *sok4
= socket (AF_INET
, SOCK_STREAM
, 0);
140 net_set_socket_options (*sok4
);
144 udp_sockets (int *sok4
, int *sok6
)
146 *sok4
= socket (AF_INET
, SOCK_DGRAM
, 0);
151 net_store_fill_any (netstore
*ns
)
153 ns
->addr
.sin_family
= AF_INET
;
154 ns
->addr
.sin_addr
.s_addr
= INADDR_ANY
;
155 ns
->addr
.sin_port
= 0;
159 net_store_fill_v4 (netstore
*ns
, guint32 addr
, int port
)
161 ns
->addr
.sin_family
= AF_INET
;
162 ns
->addr
.sin_addr
.s_addr
= addr
;
163 ns
->addr
.sin_port
= port
;
167 net_getsockaddr_v4 (netstore
*ns
)
169 return ns
->addr
.sin_addr
.s_addr
;
173 net_getsockport (int sok4
, int sok6
)
175 struct sockaddr_in addr
;
176 int len
= sizeof (addr
);
178 if (getsockname (sok4
, (struct sockaddr
*)&addr
, &len
) == -1)
180 return addr
.sin_port
;
185 /* =================== IPV6 ================== */
188 net_resolve (netstore
* ns
, char *hostname
, int port
, char **real_host
)
190 struct addrinfo hints
;
191 char ipstring
[MAX_HOSTNAME
];
192 char portstring
[MAX_HOSTNAME
];
195 /* if (ns->ip6_hostent)
196 freeaddrinfo (ns->ip6_hostent);*/
198 sprintf (portstring
, "%d", port
);
200 memset (&hints
, 0, sizeof (struct addrinfo
));
201 hints
.ai_family
= PF_UNSPEC
; /* support ipv6 and ipv4 */
202 hints
.ai_flags
= AI_CANONNAME
;
203 hints
.ai_socktype
= SOCK_STREAM
;
206 ret
= getaddrinfo (hostname
, NULL
, &hints
, &ns
->ip6_hostent
);
208 ret
= getaddrinfo (hostname
, portstring
, &hints
, &ns
->ip6_hostent
);
212 #ifdef LOOKUPD /* See note about lookupd above the IPv4 version of net_resolve. */
213 struct addrinfo
*tmp
;
216 for (tmp
= ns
->ip6_hostent
; tmp
; tmp
= tmp
->ai_next
)
219 count
= RAND_INT(count
);
221 while (count
--) ns
->ip6_hostent
= ns
->ip6_hostent
->ai_next
;
224 /* find the numeric IP number */
226 getnameinfo (ns
->ip6_hostent
->ai_addr
, ns
->ip6_hostent
->ai_addrlen
,
227 ipstring
, sizeof (ipstring
), NULL
, 0, NI_NUMERICHOST
);
229 if (ns
->ip6_hostent
->ai_canonname
)
230 *real_host
= strdup (ns
->ip6_hostent
->ai_canonname
);
232 *real_host
= strdup (hostname
);
234 return strdup (ipstring
);
237 /* the only thing making this interface unclean, this shitty sok4, sok6 business */
240 net_connect (netstore
* ns
, int sok4
, int sok6
, int *sok_return
)
242 struct addrinfo
*res
, *res0
;
245 res0
= ns
->ip6_hostent
;
247 for (res
= res0
; res
; res
= res
->ai_next
)
249 /* sok = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
252 switch (res
->ai_family
)
255 error
= connect (sok4
, res
->ai_addr
, res
->ai_addrlen
);
259 error
= connect (sok6
, res
->ai_addr
, res
->ai_addrlen
);
274 net_bind (netstore
* tobindto
, int sok4
, int sok6
)
276 bind (sok4
, tobindto
->ip6_hostent
->ai_addr
,
277 tobindto
->ip6_hostent
->ai_addrlen
);
278 bind (sok6
, tobindto
->ip6_hostent
->ai_addr
,
279 tobindto
->ip6_hostent
->ai_addrlen
);
283 net_sockets (int *sok4
, int *sok6
)
285 *sok4
= socket (AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
286 *sok6
= socket (AF_INET6
, SOCK_STREAM
, IPPROTO_TCP
);
287 net_set_socket_options (*sok4
);
288 net_set_socket_options (*sok6
);
292 udp_sockets (int *sok4
, int *sok6
)
294 *sok4
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
295 *sok6
= socket (AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
298 /* the following functions are used only by MSPROXY and are not
299 proper ipv6 implementations - do not use in new code! */
302 net_store_fill_any (netstore
*ns
)
305 struct sockaddr_in
*sin
;
307 ai
= ns
->ip6_hostent
;
309 ai
= malloc (sizeof (struct addrinfo
));
310 memset (ai
, 0, sizeof (struct addrinfo
));
311 ns
->ip6_hostent
= ai
;
313 sin
= (struct sockaddr_in
*)ai
->ai_addr
;
315 sin
= malloc (sizeof (struct sockaddr_in
));
316 memset (sin
, 0, sizeof (struct sockaddr_in
));
317 ai
->ai_addr
= (struct sockaddr
*)sin
;
319 ai
->ai_family
= AF_INET
;
320 ai
->ai_addrlen
= sizeof(struct sockaddr_in
);
321 sin
->sin_family
= AF_INET
;
322 sin
->sin_addr
.s_addr
= INADDR_ANY
;
328 net_store_fill_v4 (netstore
*ns
, guint32 addr
, int port
)
331 struct sockaddr_in
*sin
;
333 ai
= ns
->ip6_hostent
;
335 ai
= malloc (sizeof (struct addrinfo
));
336 memset (ai
, 0, sizeof (struct addrinfo
));
337 ns
->ip6_hostent
= ai
;
339 sin
= (struct sockaddr_in
*)ai
->ai_addr
;
341 sin
= malloc (sizeof (struct sockaddr_in
));
342 memset (sin
, 0, sizeof (struct sockaddr_in
));
343 ai
->ai_addr
= (struct sockaddr
*)sin
;
345 ai
->ai_family
= AF_INET
;
346 ai
->ai_addrlen
= sizeof(struct sockaddr_in
);
347 sin
->sin_family
= AF_INET
;
348 sin
->sin_addr
.s_addr
= addr
;
349 sin
->sin_port
= port
;
354 net_getsockaddr_v4 (netstore
*ns
)
357 struct sockaddr_in
*sin
;
359 ai
= ns
->ip6_hostent
;
361 while (ai
->ai_family
!= AF_INET
) {
366 sin
= (struct sockaddr_in
*)ai
->ai_addr
;
367 return sin
->sin_addr
.s_addr
;
371 net_getsockport (int sok4
, int sok6
)
373 struct sockaddr_in addr
;
374 int len
= sizeof (addr
);
376 if (getsockname (sok4
, (struct sockaddr
*)&addr
, &len
) == -1)
378 return addr
.sin_port
;