forked from mirrors/tftp-hpa-google
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:
parent
7fe0fb941c
commit
28f22b6591
9 changed files with 574 additions and 185 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue