From 158d69d419595ba2c79e85b9d6d0d9b324654433 Mon Sep 17 00:00:00 2001 From: Dean Jansa Date: Fri, 3 Sep 2010 12:57:38 -0500 Subject: update btime and hbeat libs to understand ipv6 as well as ipv4. --- btime.c | 100 ++++++++++++++++++++++++++++++++++++++++----------------------- btimed.c | 2 +- hbeat.c | 30 ++++++++++++------- 3 files changed, 83 insertions(+), 49 deletions(-) diff --git a/btime.c b/btime.c index b3a9334..bf90f1c 100644 --- a/btime.c +++ b/btime.c @@ -31,7 +31,7 @@ #include "btime_int.h" -static int same_addr(struct sockaddr_in *a, struct sockaddr_in *b); +static int same_addr(struct sockaddr_storage *a, struct sockaddr_storage *b); static void gen_cookie(char *s); /* * btime -- @@ -49,55 +49,70 @@ btime(const char *host) int sd; char cookie[BTIME_MSGLEN]; char response[BTIME_MSGLEN]; - struct sockaddr_in serv_addr; - struct sockaddr_in my_addr; - struct sockaddr_in resp_addr; - socklen_t serv_addr_len; + struct addrinfo *serv_ail, *serv_aip; + struct addrinfo *my_ail, *my_aip; + struct sockaddr_storage resp_addr; + struct addrinfo hints; socklen_t resp_addr_len; - struct hostent *hostent; - in_addr_t inaddr; unsigned int btime = 0; ssize_t nbytes; int retry; fd_set sdset; struct timeval timeout; - if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - fprintf(stderr, "Could not create socket: %s\n", - strerror(errno)); + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if (getaddrinfo(host, "23456", &hints, &serv_ail) != 0) { + fprintf(stderr, "Could not get address info for %s: %s\n", + host, strerror(errno)); return 0; } + + for (serv_aip = serv_ail; serv_aip != NULL; serv_aip = serv_aip->ai_next) { + if ((sd = socket(serv_aip->ai_family, serv_aip->ai_socktype, + serv_aip->ai_protocol)) < 0) { + continue; + } - memset(&serv_addr, 0, sizeof serv_addr); - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(BTIME_PORT); + break; + } - if ((inaddr = inet_addr(host)) != INADDR_NONE) { - memcpy(&serv_addr.sin_addr, &inaddr, sizeof inaddr); - } else { - if ((hostent = gethostbyname(host)) == NULL) { - return 0; + if (serv_aip == NULL) { + fprintf(stderr, "Could not create socket: %s\n", strerror(errno)); + freeaddrinfo(serv_ail); + return 0; + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; /* Fill in my IP for me */ + if (getaddrinfo(NULL, "0", &hints, &my_ail) != 0) { + fprintf(stderr, "Could not get address info for myself!: %s\n", strerror(errno)); + return 0; + } + + for (my_aip = my_ail; my_aip != NULL; my_aip = my_aip->ai_next) { + if (bind(sd, my_aip->ai_addr, my_aip->ai_addrlen) < 0) { + continue; } - memcpy(&serv_addr.sin_addr, hostent->h_addr, hostent->h_length); + break; } - memset(&my_addr, 0, sizeof my_addr); - my_addr.sin_family = AF_INET; - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); - my_addr.sin_port = htons(0); - if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { + if (my_aip == NULL) { fprintf(stderr, "Could not bind to local address: %s\n", - strerror(errno)); + strerror(errno)); + freeaddrinfo(my_ail); return 0; } memset(cookie, 0, BTIME_MSGLEN); gen_cookie(cookie); for (retry = 0; retry < MAX_RETRY; retry++) { - serv_addr_len = sizeof serv_addr; if ((nbytes = sendto(sd, &cookie, BTIME_MSGLEN, MSG_DONTWAIT, - (struct sockaddr *)&serv_addr, serv_addr_len)) < 0) { + serv_aip->ai_addr, serv_aip->ai_addrlen)) < 0) { if (errno == EAGAIN) { usleep(retry * 100); } else { @@ -140,14 +155,15 @@ btime(const char *host) retry = 1; continue; } - } else if (!same_addr(&serv_addr, &resp_addr)) { + } else if (!same_addr((struct sockaddr_storage *)serv_aip->ai_addr, &resp_addr)) { /* If no cookie, check peer */ - char *rstr = strdup(inet_ntoa(resp_addr.sin_addr)); - char *sstr = strdup(inet_ntoa(serv_addr.sin_addr)); + char rstr[NI_MAXHOST]; + char sstr[NI_MAXHOST]; + + inet_ntop(resp_addr.ss_family, &resp_addr, rstr, NI_MAXHOST); + inet_ntop(serv_aip->ai_family, serv_aip->ai_addr, sstr, NI_MAXHOST); fprintf(stderr, "Got response from %s instead of %s\n", rstr, sstr); - free(rstr); - free(sstr); retry = 1; continue; } else { @@ -158,28 +174,38 @@ btime(const char *host) } while (retry); close(sd); + freeaddrinfo(serv_ail); + freeaddrinfo(my_ail); return btime; } /* same_addr * - * Compare to struct sockaddr_in's + * Compare two struct sockaddr_storage * * Returns: * 1 if the addresses match * 0 if the addresses are different */ static int -same_addr(struct sockaddr_in *a, struct sockaddr_in *b) +same_addr(struct sockaddr_storage *a, struct sockaddr_storage *b) { - if (a->sin_family != b->sin_family) { - return 0; - } else if (a->sin_addr.s_addr != b->sin_addr.s_addr) { + return 1; + if (a->ss_family != b->ss_family) { return 0; + } else if ((a->ss_family == AF_INET) + && (((struct sockaddr_in *)a)->sin_addr.s_addr + != ((struct sockaddr_in *)b)->sin_addr.s_addr)) { + return 0; + } else if ((a->ss_family == AF_INET6) + && (((struct sockaddr_in6 *)a)->sin6_addr.s6_addr + != ((struct sockaddr_in6 *)b)->sin6_addr.s6_addr)) { + return 0; } else { return 1; } + } /* gen_cookie * diff --git a/btimed.c b/btimed.c index 83a5af6..0ba6c91 100644 --- a/btimed.c +++ b/btimed.c @@ -44,7 +44,7 @@ main(int argc, char **argv) char btimeonly[BTIME_MSGLEN]; char cookiemsg[BTIME_MSGLEN]; char *outmsg; - struct sockaddr_in cli_addr; + struct sockaddr_storage cli_addr; socklen_t cli_addr_len; ssize_t nbytes; unsigned int local_btime; diff --git a/hbeat.c b/hbeat.c index 46b8ac1..8f781e0 100644 --- a/hbeat.c +++ b/hbeat.c @@ -56,25 +56,33 @@ hbeat_t hbeat_init(const char *host, int max_timeout) { struct hbeat_s *hbeatp; - struct hostent *hostent; - struct in_addr tmpaddr; + struct addrinfo hints, *aip; + void *addr; + char ipstr[INET6_ADDRSTRLEN]; hbeatp = malloc(sizeof *hbeatp); if (!hbeatp) { return NULL; } - /* Store the dotted quad instead of the hostname so we - * don't have to look it up ever time we hbeat. */ - if (inet_addr(host) == INADDR_NONE) { - if ((hostent = gethostbyname(host)) == NULL) { - return NULL; - } - memcpy(&tmpaddr, hostent->h_addr, hostent->h_length); - hbeatp->host = strdup(inet_ntoa(tmpaddr)); + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + if (getaddrinfo(host, NULL, &hints, &aip) != 0) { + return NULL; + } + + if (aip->ai_family == AF_INET) { + addr = &(((struct sockaddr_in *)aip->ai_addr)->sin_addr); } else { - hbeatp->host = strdup(host); + addr = &(((struct sockaddr_in6 *)aip->ai_addr)->sin6_addr); } + + inet_ntop(aip->ai_family, addr, ipstr, sizeof ipstr); + freeaddrinfo(aip); + + hbeatp->host = strdup(ipstr); hbeatp->max_timeout = max_timeout; hbeatp->rhost_state = HOST_ALIVE; hbeatp->last_rhost_btime = 0; -- cgit From e96e56146dc7c11d388d25db42383993b87e8791 Mon Sep 17 00:00:00 2001 From: Dean Jansa Date: Fri, 3 Sep 2010 14:05:23 -0500 Subject: Shouldn't need to restrict btimed to IPv4 now. --- btimed.xinetd | 1 - 1 file changed, 1 deletion(-) diff --git a/btimed.xinetd b/btimed.xinetd index 72e8244..ab8d1ff 100644 --- a/btimed.xinetd +++ b/btimed.xinetd @@ -10,5 +10,4 @@ service btimed wait = yes user = root server = /usr/sbin/btimed - flags = IPV4 } -- cgit From edf6032e3395baa5e2a160e4f70d3b108ae31622 Mon Sep 17 00:00:00 2001 From: Dean Jansa Date: Tue, 28 Sep 2010 15:53:28 -0500 Subject: First crack at ipv6/ipv4 agnostic qarsh/qacp. --- qacp.c | 9 +++-- qarsh.c | 9 +++-- qarshd.c | 19 ++++++--- sockutil.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++-------------- sockutil.h | 6 +-- 5 files changed, 125 insertions(+), 47 deletions(-) diff --git a/qacp.c b/qacp.c index 6ddf414..c6c143e 100644 --- a/qacp.c +++ b/qacp.c @@ -49,6 +49,7 @@ /* Globals */ int qacp_fd = -1; /* The control connection to qacpd */ +unsigned short qarsh_ss_family; /* AF_INET/AF_INET6, set on connect */ short quiet = 0; void @@ -148,7 +149,7 @@ qacp_sendonefile(const char *host, const char *srcfile, const char *destfile) exit(errno); } - sd = bind_any(QARSH_MINPORT); + sd = bind_any(QARSH_MINPORT, qarsh_ss_family); port = getsockport(sd); /* Recall that the packet types are qarshd-centric, so if we want @@ -251,7 +252,7 @@ qacp_recvonefile(const char *host, const char *srcfile, const char *destfile) fchmod(outfd, rstatp->qp_st_mode); - sd = bind_any(QARSH_MINPORT); + sd = bind_any(QARSH_MINPORT, qarsh_ss_family); port = getsockport(sd); /* Recall that the packet types are qarshd-centric, so if we want @@ -420,7 +421,7 @@ recvfiles(char **argv, int argc, int fileidx, short recursive) ruser = strdup(pw->pw_name); } - qacp_fd = connect_to_host(rhost, QARSHD_CONTROL_PORT); + qacp_fd = connect_to_host(rhost, QARSHD_CONTROL_PORT, &qarsh_ss_family); if (qacp_fd == -1) { if (errno == 0) { fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", @@ -526,7 +527,7 @@ sendfiles(char **argv, int argc, int fileidx, short recursive) ruser = strdup(pw->pw_name); } - qacp_fd = connect_to_host(rhost, QARSHD_CONTROL_PORT); + qacp_fd = connect_to_host(rhost, QARSHD_CONTROL_PORT, &qarsh_ss_family); if (qacp_fd == -1) { if (errno == 0) { fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", diff --git a/qarsh.c b/qarsh.c index 6575bd0..116779d 100644 --- a/qarsh.c +++ b/qarsh.c @@ -50,6 +50,7 @@ /* Globals */ int qarsh_fd = -1; /* The control connection to qarshd */ +unsigned short qarsh_ss_family; /* AF_INET/AF_INET6, set on connect */ hbeat_t qarsh_hb; /* Heartbeat handle */ int signal_to_send = 0; int sigs_to_propogate[] = { SIGINT, SIGTERM, SIGHUP, SIGUSR1, SIGUSR2 }; @@ -191,11 +192,11 @@ run_remote_cmd(char *cmdline) struct timespec timeout; short cmd_finished; - l_in = bind_any(QARSH_MINPORT); + l_in = bind_any(QARSH_MINPORT, qarsh_ss_family); p_in = getsockport(l_in); - l_out = bind_any(QARSH_MINPORT); + l_out = bind_any(QARSH_MINPORT, qarsh_ss_family); p_out = getsockport(l_out); - l_err = bind_any(QARSH_MINPORT); + l_err = bind_any(QARSH_MINPORT, qarsh_ss_family); p_err = getsockport(l_err); qp = make_qp_runcmd(cmdline, p_in, p_out, p_err); @@ -508,7 +509,7 @@ again: sigaction(SIGALRM, &sa, NULL); alarm(max_timeout); - qarsh_fd = connect_to_host(host, port); + qarsh_fd = connect_to_host(host, port, &qarsh_ss_family); alarm(0); if (qarsh_fd == -1) { diff --git a/qarshd.c b/qarshd.c index ec5d1f7..fd4ca08 100644 --- a/qarshd.c +++ b/qarshd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,7 @@ int debug = 0; /* Globals */ -struct sockaddr_in peername; +struct sockaddr_storage peername; int child_exitted = 0; /* A mini cache for rstat so we can check it in pushfile */ @@ -384,7 +385,9 @@ int main(int argc, char *argv[]) { int ch; - socklen_t peernamelen; + socklen_t peerlen; + char peer_hoststr[NI_MAXHOST]; + char peer_portstr[NI_MAXSERV]; openlog("qarshd", LOG_PID, LOG_DAEMON); @@ -401,10 +404,14 @@ main(int argc, char *argv[]) } /* daemon initialization */ - peernamelen = sizeof peername; - getpeername(0, (struct sockaddr *)&peername, &peernamelen); - syslog(LOG_INFO, "Talking to peer %s:%d", - inet_ntoa(peername.sin_addr), ntohs(peername.sin_port)); + peerlen = sizeof peername; + getpeername(0, (struct sockaddr *)&peername, &peerlen); + getnameinfo((struct sockaddr *)&peername, peerlen, + peer_hoststr, NI_MAXHOST, peer_portstr, + NI_MAXSERV, NI_NUMERICHOST); + syslog(LOG_INFO, "Talking to peer %s:%s (%s)", peer_hoststr, peer_portstr, + peername.ss_family == AF_INET ? "IPv4" : "IPv6"); + /* Start reading packets from stdin */ handle_packets(0); diff --git a/sockutil.c b/sockutil.c index 05097b2..6e74993 100644 --- a/sockutil.c +++ b/sockutil.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -35,30 +36,48 @@ int getsockport(int sd) { - struct sockaddr_in addr; + struct sockaddr_storage addr; socklen_t addrlen; addrlen = sizeof addr; if (getsockname(sd, (struct sockaddr *)&addr, &addrlen) == 0) { - return ntohs(addr.sin_port); + if (addr.ss_family == AF_INET) { + struct sockaddr_in *ipv4p = (struct sockaddr_in *)&addr; + return ntohs(ipv4p->sin_port); + } else { + struct sockaddr_in6 *ipv6p = (struct sockaddr_in6 *)&addr; + return ntohs(ipv6p->sin6_port); + } } else { return -1; } } int -bind_any(int minport) +bind_any(int minport, unsigned short ss_family) { int sd; - struct sockaddr_in addr; + struct sockaddr_storage addr; - sd = socket(AF_INET, SOCK_STREAM, 0); + sd = socket(ss_family, SOCK_STREAM, 0); if (sd == -1) return -1; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - do { - addr.sin_port = htons(minport++); - } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); + + if (ss_family == AF_INET) { + struct sockaddr_in *ipv4p = (struct sockaddr_in *)&addr; + ipv4p->sin_family = AF_INET; + ipv4p->sin_addr.s_addr = htonl(INADDR_ANY); + do { + ipv4p->sin_port = htons(minport++); + } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); + } else { + struct sockaddr_in6 *ipv6p = (struct sockaddr_in6 *)&addr; + ipv6p->sin6_family = AF_INET6; + ipv6p->sin6_addr = in6addr_any; + do { + ipv6p->sin6_port = htons(minport++); + } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); + } + if (listen(sd, 0) == -1) { syslog(LOG_WARNING, "listen error %d, %s", errno, strerror(errno)); @@ -67,39 +86,89 @@ bind_any(int minport) } int -connect_to_host(char *hostname, int port) +connect_to_host(char *hostname, int port, unsigned short *ss_family) { - struct hostent *h; - struct sockaddr_in haddr; + struct addrinfo *ail; + struct addrinfo *aip; + struct addrinfo hints; + char portstr[NI_MAXSERV]; int sd; + int err; - if ((h = gethostbyname(hostname)) == NULL) { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + memset(portstr, 0, sizeof portstr); + snprintf(portstr, NI_MAXSERV, "%d", port); + + if ((err = getaddrinfo(hostname, portstr, NULL, &ail)) != 0) { + fprintf(stderr, "Could not resolve hostname %s: %s\n", + hostname, gai_strerror(err)); return -1; } - haddr.sin_family = h->h_addrtype; - haddr.sin_port = htons(port); - memcpy(&haddr.sin_addr, h->h_addr, h->h_length); - sd = socket(PF_INET, SOCK_STREAM, 0); - if (sd == -1) return -1; - if (connect(sd, (struct sockaddr *)&haddr, sizeof haddr) == -1) { - return -1; + /* TBD -- do we loop over all of the addrinfos returned trying to + * connect, or just pick the first one? */ + + for (aip = ail; aip != NULL; aip = aip->ai_next) { +#if 0 + char hname[NI_MAXHOST] = ""; + char nname[NI_MAXHOST] = ""; + + err = getnameinfo(aip->ai_addr, aip->ai_addrlen, hname, NI_MAXHOST, NULL, 0, 0); + err = getnameinfo(aip->ai_addr, aip->ai_addrlen, nname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + + if (err != 0) { + printf("error in getnameinfo: %s\n", gai_strerror(err)); + continue; + } + + if (*hname && *nname) { + printf("Trying: %s (%s) -- ", hname, nname); + if (aip->ai_family == AF_INET6) puts("IPv6"); + if (aip->ai_family == AF_INET) puts("IPv4"); + } +#endif + + sd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); + if (sd == -1) return -1; + if (connect(sd, aip->ai_addr, aip->ai_addrlen) == -1) { + close(sd); + continue; + } else { + *ss_family=aip->ai_family; + freeaddrinfo(ail); + return sd; + } } - return sd; + + freeaddrinfo(ail); + return -1; } int -connect_to_peer(struct sockaddr_in *peer, int port) +connect_to_peer(struct sockaddr_storage *peer, int port) { - struct sockaddr_in in_peer; int sd; int fdflags; + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + struct sockaddr_storage *peeraddr; + + if (peer->ss_family == AF_INET) { + ipv4.sin_family = AF_INET; + ipv4.sin_port=htons(port); + ipv4.sin_addr = ((struct sockaddr_in *)peer)->sin_addr; + peeraddr = (struct sockaddr_storage *)&ipv4; + } else { + ipv6.sin6_family = AF_INET6; + ipv6.sin6_port=htons(port); + ipv6.sin6_addr = ((struct sockaddr_in6 *)peer)->sin6_addr; + peeraddr = (struct sockaddr_storage *)&ipv6; + } - in_peer.sin_family = AF_INET; - in_peer.sin_port = htons(port); - in_peer.sin_addr = peer->sin_addr; - - sd = socket(PF_INET, SOCK_STREAM, 0); + sd = socket(peer->ss_family, SOCK_STREAM, 0); if (sd == -1) return -1; /* Set close-on-exec for these sds */ @@ -112,7 +181,7 @@ connect_to_peer(struct sockaddr_in *peer, int port) return -1; } - if (connect(sd, (struct sockaddr *)&in_peer, sizeof in_peer) == -1) { + if (connect(sd, (struct sockaddr *)peeraddr, sizeof *peeraddr) == -1) { return -1; } return sd; diff --git a/sockutil.h b/sockutil.h index 820376f..3678b1f 100644 --- a/sockutil.h +++ b/sockutil.h @@ -20,8 +20,8 @@ #include int getsockport(int sd); -int bind_any(int minport); -int connect_to_host(char *hostname, int port); -int connect_to_peer(struct sockaddr_in *peer, int port); +int bind_any(int minport, unsigned short ss_family); +int connect_to_host(char *hostname, int port, unsigned short *ss_family); +int connect_to_peer(struct sockaddr_storage *peer, int port); struct qa_packet * recv_packet(int fd); int send_packet(int fd, struct qa_packet *qp); -- cgit