Add support for IPv6 in the server and client.

Add support for IPv6 in the server and client.
You can force the use of IPv4 or IPv6 only with new
-4 and -6 commandline options, if IPv6 support was compiled in.

Signed-off-by: Karsten Keil <kkeil@suse.de>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
Karsten Keil 2008-07-23 18:32:21 +02:00 committed by H. Peter Anvin
parent 7fe0fb941c
commit 28f22b6591
9 changed files with 574 additions and 185 deletions

View file

@ -237,7 +237,7 @@ int synchnet(int f)
{ /* socket to flush */
int pktcount = 0;
char rbuf[PKTSIZE];
struct sockaddr_in from;
union sock_addr from;
socklen_t fromlen;
fd_set socketset;
struct timeval notime;
@ -253,15 +253,15 @@ int synchnet(int f)
/* Otherwise drain the packet */
pktcount++;
fromlen = sizeof from;
fromlen = sizeof(from);
(void)recvfrom(f, rbuf, sizeof(rbuf), 0,
(struct sockaddr *)&from, &fromlen);
&from.sa, &fromlen);
}
return pktcount; /* Return packets drained */
}
int pick_port_bind(int sockfd, struct sockaddr_in *myaddr,
int pick_port_bind(int sockfd, union sock_addr *myaddr,
unsigned int port_range_from,
unsigned int port_range_to)
{
@ -279,9 +279,8 @@ int pick_port_bind(int sockfd, struct sockaddr_in *myaddr,
port = firstport;
do {
myaddr->sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *)myaddr, sizeof *myaddr) < 0) {
sa_set_port(myaddr, htons(port));
if (bind(sockfd, &myaddr->sa, SOCKLEN(myaddr)) < 0) {
/* Some versions of Linux return EINVAL instead of EADDRINUSE */
if (!(port_range && (errno == EINVAL || errno == EADDRINUSE)))
return -1;
@ -299,3 +298,34 @@ int pick_port_bind(int sockfd, struct sockaddr_in *myaddr,
return -1;
}
int
set_sock_addr(char *host,union sock_addr *s, char **name)
{
struct addrinfo *addrResult;
struct addrinfo hints;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_family = s->sa.sa_family;
hints.ai_flags = AI_CANONNAME;
err = getaddrinfo(host, NULL, &hints, &addrResult);
if (err) {
printf("Error : %s\n", gai_strerror(err));
printf("%s: unknown host\n", host);
return err;
}
if (addrResult == NULL) {
printf("%s: unknown host\n", host);
return EAI_NONAME;
}
memcpy(s, addrResult->ai_addr, addrResult->ai_addrlen);
if (name) {
if (addrResult->ai_canonname)
*name = xstrdup(addrResult->ai_canonname);
else
*name = xstrdup(host);
}
freeaddrinfo(addrResult);
return 0;
}

View file

@ -40,6 +40,58 @@
#include "config.h"
union sock_addr {
struct sockaddr sa;
struct sockaddr_in si;
#ifdef HAVE_IPV6
struct sockaddr_in6 s6;
#endif
};
#define SOCKLEN(sock) \
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
(sizeof(struct sockaddr_in)) : \
(sizeof(union sock_addr)))
#ifdef HAVE_IPV6
#define SOCKPORT(sock) \
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
((union sock_addr*)sock)->si.sin_port : \
((union sock_addr*)sock)->s6.sin6_port)
#else
#define SOCKPORT(sock) \
(((union sock_addr*)sock)->si.sin_port)
#endif
#ifdef HAVE_IPV6
#define SOCKADDR_P(sock) \
(((union sock_addr*)sock)->sa.sa_family == AF_INET ? \
(void *)&((union sock_addr*)sock)->si.sin_addr : \
(void *)&((union sock_addr*)sock)->s6.sin6_addr)
#else
#define SOCKADDR_P(sock) \
(void *)&((union sock_addr*)sock)->si.sin_addr
#endif
static inline int sa_set_port(union sock_addr *s, u_short port)
{
switch (s->sa.sa_family) {
case AF_INET:
s->si.sin_port = port;
break;
#ifdef HAVE_IPV6
case AF_INET6:
s->s6.sin6_port = port;
break;
#endif
default:
return -1;
}
return 0;
}
int set_sock_addr(char *, union sock_addr *, char **);
struct tftphdr;
struct tftphdr *r_init(void);
@ -55,7 +107,7 @@ int writeit(FILE *, struct tftphdr **, int, int);
extern int segsize;
#define MAX_SEGSIZE 65464
int pick_port_bind(int sockfd, struct sockaddr_in *myaddr,
int pick_port_bind(int sockfd, union sock_addr *myaddr,
unsigned int from, unsigned int to);
#endif