26 |
|
#include <string.h> |
27 |
|
#include <sys/types.h> |
28 |
|
#include <sys/socket.h> |
29 |
+ |
#include <netdb.h> |
30 |
|
#include <netinet/in.h> |
31 |
|
#include <arpa/inet.h> |
32 |
|
#include <poll.h> |
83 |
|
static unsigned int IRC_RAW_LEN = 0; /* Position of IRC_RAW */ |
84 |
|
static int IRC_FD = 0; /* File descriptor for IRC client */ |
85 |
|
|
86 |
< |
static struct sockaddr_in IRC_SVR; /* Sock Address Struct for IRC server */ |
86 |
< |
static struct in_addr IRC_LOCAL; /* Sock Address Struct for Bind */ |
86 |
> |
static struct sockaddr_storage IRC_SVR; /* Sock Address Struct for IRC server */ |
87 |
|
|
88 |
|
static time_t IRC_LAST = 0; /* Last full line of data from irc server*/ |
89 |
|
static time_t IRC_LASTRECONNECT = 0; /* Time of last reconnection */ |
168 |
|
static void |
169 |
|
irc_init(void) |
170 |
|
{ |
171 |
< |
struct sockaddr_in bsaddr; |
172 |
< |
struct in_addr *irc_host; |
171 |
> |
const void *address = NULL; |
172 |
|
|
173 |
|
if (IRC_FD) |
174 |
|
close(IRC_FD); |
175 |
|
|
176 |
|
memset(&IRC_SVR, 0, sizeof(IRC_SVR)); |
178 |
– |
memset(&IRC_LOCAL, 0, sizeof(IRC_LOCAL)); |
179 |
– |
memset(&bsaddr, 0, sizeof(bsaddr)); |
177 |
|
|
178 |
|
/* Resolve IRC host. */ |
179 |
< |
if ((irc_host = firedns_resolveip4(IRCItem->server)) == NULL) |
179 |
> |
if ((address = firedns_resolveip6(IRCItem->server))) |
180 |
|
{ |
181 |
< |
log_printf("IRC -> firedns_resolveip4(\"%s\"): %s", IRCItem->server, |
185 |
< |
firedns_strerror(fdns_errno)); |
186 |
< |
exit(EXIT_FAILURE); |
187 |
< |
} |
181 |
> |
struct sockaddr_in6 *in = (struct sockaddr_in6 *)&IRC_SVR; |
182 |
|
|
183 |
< |
IRC_SVR.sin_family = AF_INET; |
184 |
< |
IRC_SVR.sin_port = htons(IRCItem->port); |
185 |
< |
IRC_SVR.sin_addr = *irc_host; |
183 |
> |
IRC_SVR.ss_family = AF_INET6; |
184 |
> |
in->sin6_port = htons(IRCItem->port); |
185 |
> |
memcpy(&in->sin6_addr, address, sizeof(in->sin6_addr)); |
186 |
> |
} |
187 |
> |
else if ((address = firedns_resolveip4(IRCItem->server))) |
188 |
> |
{ |
189 |
> |
struct sockaddr_in *in = (struct sockaddr_in *)&IRC_SVR; |
190 |
|
|
191 |
< |
if (IRC_SVR.sin_addr.s_addr == INADDR_NONE) |
191 |
> |
IRC_SVR.ss_family = AF_INET; |
192 |
> |
in->sin_port = htons(IRCItem->port); |
193 |
> |
memcpy(&in->sin_addr, address, sizeof(in->sin_addr)); |
194 |
> |
} |
195 |
> |
else |
196 |
|
{ |
197 |
< |
log_printf("IRC -> Unknown error resolving remote host (%s)", |
198 |
< |
IRCItem->server); |
197 |
> |
log_printf("IRC -> firedns_resolveip(\"%s\"): %s", IRCItem->server, |
198 |
> |
firedns_strerror(fdns_errno)); |
199 |
|
exit(EXIT_FAILURE); |
200 |
|
} |
201 |
|
|
202 |
|
/* Request file desc for IRC client socket */ |
203 |
< |
IRC_FD = socket(AF_INET, SOCK_STREAM, 0); |
203 |
> |
IRC_FD = socket(IRC_SVR.ss_family, SOCK_STREAM, 0); |
204 |
|
|
205 |
|
if (IRC_FD == -1) |
206 |
|
{ |
211 |
|
/* Bind */ |
212 |
|
if (!EmptyString(IRCItem->vhost)) |
213 |
|
{ |
214 |
< |
if (inet_pton(AF_INET, IRCItem->vhost, &IRC_LOCAL.s_addr) <= 0) |
214 |
> |
struct addrinfo hints, *res; |
215 |
> |
|
216 |
> |
memset(&hints, 0, sizeof(hints)); |
217 |
> |
|
218 |
> |
hints.ai_family = AF_UNSPEC; |
219 |
> |
hints.ai_socktype = SOCK_STREAM; |
220 |
> |
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; |
221 |
> |
|
222 |
> |
if (getaddrinfo(IRCItem->vhost, NULL, &hints, &res)) |
223 |
|
{ |
224 |
|
log_printf("IRC -> bind(): %s is an invalid address", IRCItem->vhost); |
225 |
|
exit(EXIT_FAILURE); |
226 |
|
} |
227 |
< |
|
218 |
< |
bsaddr.sin_addr.s_addr = IRC_LOCAL.s_addr; |
219 |
< |
bsaddr.sin_family = AF_INET; |
220 |
< |
bsaddr.sin_port = htons(0); |
221 |
< |
|
222 |
< |
if (bind(IRC_FD, (struct sockaddr *)&bsaddr, sizeof(bsaddr))) |
227 |
> |
else if (bind(IRC_FD, res->ai_addr, res->ai_addrlen)) |
228 |
|
{ |
229 |
|
log_printf("IRC -> bind(): error binding to %s: %s", IRCItem->vhost, strerror(errno)); |
230 |
|
exit(EXIT_FAILURE); |
231 |
|
} |
232 |
+ |
|
233 |
+ |
freeaddrinfo(res); |
234 |
|
} |
235 |
|
} |
236 |
|
|
315 |
|
/* Connect to IRC server as client. */ |
316 |
|
if (connect(IRC_FD, (struct sockaddr *)&IRC_SVR, sizeof(IRC_SVR)) == -1) |
317 |
|
{ |
318 |
< |
switch (errno) |
319 |
< |
{ |
313 |
< |
case EISCONN: |
314 |
< |
/* Already connected */ |
315 |
< |
return; |
316 |
< |
case ECONNREFUSED: |
317 |
< |
log_printf("IRC -> connect(): Connection refused by (%s)", |
318 |
< |
IRCItem->server); |
319 |
< |
break; |
320 |
< |
case ETIMEDOUT: |
321 |
< |
log_printf("IRC -> connect(): Timed out connecting to (%s)", |
322 |
< |
IRCItem->server); |
323 |
< |
break; |
324 |
< |
case ENETUNREACH: |
325 |
< |
log_printf("IRC -> connect(): Network unreachable"); |
326 |
< |
break; |
327 |
< |
case EALREADY: |
328 |
< |
/* Previous attempt not complete */ |
329 |
< |
return; |
330 |
< |
default: |
331 |
< |
log_printf("IRC -> connect(): Unknown error connecting to (%s)", |
332 |
< |
IRCItem->server); |
318 |
> |
log_printf("IRC -> connect(): error connecting to %s: %s", |
319 |
> |
IRCItem->server, strerror(errno)); |
320 |
|
|
321 |
< |
if (OPT_DEBUG >= 1) |
322 |
< |
log_printf("%s", strerror(errno)); |
336 |
< |
} |
321 |
> |
if (errno == EISCONN /* Already connected */ || errno == EALREADY /* Previous attempt not complete */) |
322 |
> |
return; |
323 |
|
|
324 |
|
/* Try to connect again */ |
325 |
|
irc_reconnect(); |
668 |
|
{ |
669 |
|
node_t *node; |
670 |
|
|
671 |
< |
log_printf("IRC -> Connected to %s:%d", IRCItem->server, IRCItem->port); |
671 |
> |
log_printf("IRC -> Connected to %s/%d", IRCItem->server, IRCItem->port); |
672 |
|
|
673 |
|
/* Identify to nickserv if needed */ |
674 |
|
if (!EmptyString(IRCItem->nickserv)) |