From 927ad5776ce309ed4155e8b6a36500738304f2bb Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 20 Sep 2019 17:14:28 +0200 Subject: [PATCH] avrdude: Cherry-pick rev 1421 from upstream: Submitted by Reinhard Max patch #8311: Add IPv6 support to the -Pnet:host:port option * ser_posix.c (net_open): Rewrite to use getaddrinfo() rather than gethostbyname() Fix #2918 --- src/avrdude/ChangeLog | 9 ++++ src/avrdude/avrdude.1 | 7 +++ src/avrdude/configure.ac | 2 +- src/avrdude/doc/avrdude.texi | 5 ++ src/avrdude/ser_posix.c | 99 +++++++++++++++++++++--------------- 5 files changed, 81 insertions(+), 41 deletions(-) diff --git a/src/avrdude/ChangeLog b/src/avrdude/ChangeLog index 975f52317..879fbf957 100644 --- a/src/avrdude/ChangeLog +++ b/src/avrdude/ChangeLog @@ -1,3 +1,12 @@ +2018-01-17 Joerg Wunsch +(cherry-picked) + Submitted by Reinhard Max + patch #8311: Add IPv6 support to the -Pnet:host:port option + * ser_posix.c (net_open): Rewrite to use getaddrinfo() + rather than gethostbyname() + * avrdude.1: Document IPv6 feature + * doc/avrdude.texi: (Dito) + 2016-05-10 Joerg Wunsch Submitted by Hannes Jochriem: diff --git a/src/avrdude/avrdude.1 b/src/avrdude/avrdude.1 index 65fc7b1d6..47ca4edde 100644 --- a/src/avrdude/avrdude.1 +++ b/src/avrdude/avrdude.1 @@ -505,12 +505,19 @@ network connection to (TCP) on .Ar host is established. +Square brackets may be placed around +.Ar host +to improve readability, for numeric IPv6 addresses (e.g. +.Li net:[2001:db8::42]:1337 ) . The remote endpoint is assumed to be a terminal or console server that connects the network stream to a local serial port where the actual programmer has been attached to. The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. +.Pp +Note: The ability to handle IPv6 hostnames and addresses is limited to +Posix systems (by now). .It Fl q Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. diff --git a/src/avrdude/configure.ac b/src/avrdude/configure.ac index a23a959f2..d14fc545f 100644 --- a/src/avrdude/configure.ac +++ b/src/avrdude/configure.ac @@ -214,7 +214,7 @@ AC_HEADER_TIME AC_CHECK_LIB([ws2_32], [puts]) # Checks for library functions. -AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep]) +AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep getaddrinfo]) AC_MSG_CHECKING([for a Win32 HID libray]) SAVED_LIBS="${LIBS}" diff --git a/src/avrdude/doc/avrdude.texi b/src/avrdude/doc/avrdude.texi index 6941389df..7062a9920 100644 --- a/src/avrdude/doc/avrdude.texi +++ b/src/avrdude/doc/avrdude.texi @@ -557,6 +557,9 @@ higher level protocol (as opposed to bit-bang style programmers), In this case, instead of trying to open a local device, a TCP network connection to (TCP) @var{port} on @var{host} is established. +Square brackets may be placed around @var{host} to improve +readability for numeric IPv6 addresses (e.g. +@code{net:[2001:db8::42]:1337}). The remote endpoint is assumed to be a terminal or console server that connects the network stream to a local serial port where the actual programmer has been attached to. @@ -564,6 +567,8 @@ The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. +Note: The ability to handle IPv6 hostnames and addresses is limited to +Posix systems (by now). @item -q Disable (or quell) output of the progress bar while reading or writing diff --git a/src/avrdude/ser_posix.c b/src/avrdude/ser_posix.c index 9992f78e3..dfa02f9fe 100644 --- a/src/avrdude/ser_posix.c +++ b/src/avrdude/ser_posix.c @@ -150,6 +150,7 @@ static int ser_setspeed(union filedescriptor *fd, long baud) return 0; } +#include "ac_cfg.h" // Timeout read & write variants // Additionally to the regular -1 on I/O error, they return -2 on timeout @@ -221,23 +222,35 @@ ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout) static int net_open(const char *port, union filedescriptor *fdp) { - char *hstr, *pstr, *end; - unsigned int pnum; - int fd; - struct sockaddr_in sockaddr; - struct hostent *hp; +#ifdef HAVE_GETADDRINFO + char *hp, *hstr, *pstr; + int s, fd, ret = -1; + struct addrinfo hints; + struct addrinfo *result, *rp; - if ((hstr = strdup(port)) == NULL) { + if ((hstr = hp = strdup(port)) == NULL) { avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n", progname); return -1; } - if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) { + /* + * As numeric IPv6 addresses use colons as separators, we need to + * look for the last colon here, which separates the port number or + * service name from the host or IP address. + */ + if (((pstr = strrchr(hstr, ':')) == NULL) || (pstr == hstr)) { avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n", progname, hstr); - free(hstr); - return -1; + goto error; + } + + /* + * Remove brackets from the host part, if present. + */ + if (*hstr == '[' && *(pstr-1) == ']') { + hstr++; + *(pstr-1) = '\0'; } /* @@ -245,43 +258,49 @@ net_open(const char *port, union filedescriptor *fdp) */ *pstr++ = '\0'; - pnum = strtoul(pstr, &end, 10); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + s = getaddrinfo(hstr, pstr, &hints, &result); - if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) { - avrdude_message(MSG_INFO, "%s: net_open(): Bad port number \"%s\"\n", - progname, pstr); - free(hstr); - return -1; + if (s != 0) { + avrdude_message(MSG_INFO, + "%s: net_open(): Cannot resolve " + "host=\"%s\", port=\"%s\": %s\n", + progname, hstr, pstr, gai_strerror(s)); + goto error; } - - if ((hp = gethostbyname(hstr)) == NULL) { - avrdude_message(MSG_INFO, "%s: net_open(): unknown host \"%s\"\n", - progname, hstr); - free(hstr); - return -1; + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) { + /* This one failed, loop over */ + continue; + } + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) { + /* Success, we are connected */ + break; + } + close(fd); } - - free(hstr); - - if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", - progname, strerror(errno)); - return -1; + if (rp == NULL) { + avrdude_message(MSG_INFO, "%s: net_open(): Cannot connect: %s\n", + progname, strerror(errno)); } - - memset(&sockaddr, 0, sizeof(struct sockaddr_in)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(pnum); - memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr)); - - if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { - avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", - progname, strerror(errno)); - return -1; + else { + fdp->ifd = fd; + ret = 0; } + freeaddrinfo(result); - fdp->ifd = fd; - return 0; +error: + free(hp); + return ret; +#else + avrdude_message(MSG_INFO, + "%s: Networking is not supported on your platform.\n" + "If you need it, please open a bug report.\n", progname); + return -1; +#endif /* HAVE_GETADDRINFO */ }