https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=644998 --- options.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/options.c b/options.c index a075357..efff2c7 100644 --- a/options.c +++ b/options.c @@ -6,8 +6,13 @@
#include "config.h"
+#ifdef __linux__ +#define _GNU_SOURCE +#endif + #include <sys/types.h>
+#include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -90,6 +95,72 @@ static int is_bad_interface_name(char *i) { return 0; }
+/* none of these errors are expected, so I think it is OK to print them */ +static char *get_interface_for_default_ipv4_route(void) { +#ifdef __linux__ + pid_t pid; + int fds[2]; + int r; + char buf[4096]; + char *p, *q; + + r = pipe2(fds, O_CLOEXEC); + if (r < 0) { + fprintf(stderr, "get_interface_for_default_ipv4_route: pipe() failed: %s, continuing...", strerror(r)); + return NULL; + } + pid = fork(); + if (pid < 0) { + fprintf(stderr, "get_interface_for_default_ipv4_route: fork() failed: %s, continuing...", strerror(r)); + return NULL; + } else if (pid == 0) { + /* child */ + r = dup2(fds[0], STDOUT_FILENO); + if (r < 0) { + char buf[1] = {'\n'}; + + /* we have to write something as the other end is expecting something */ + r = write(fds[0], &buf, sizeof(buf)); + _exit(EXIT_FAILURE); + } + + execlp("ip", /* add "-6", here to make default IPv6 route */ "route", NULL); + char buf[1] = {'\n'}; + + /* we have to write something as the other end is expecting something */ + r = write(fds[0], &buf, sizeof(buf)); + _exit(EXIT_FAILURE); + } + /* parent */ + close(fds[1]); + r = read(fds[1], &buf, sizeof(buf)); + if (r < 0) { + fprintf(stderr, "get_interface_for_default_ipv4_route: read() failed: %s, continuing...", strerror(r)); + return NULL; + } + + p = strstr((char *)&buf, "default via "); + if (!p) + return NULL; + p += strlen("default via "); + q = p; + for (;*p != '\n' && *p; p++) + ; + *p = '\0'; + p = strstr(q, " dev "); + if (!p) + return NULL; + p += strlen(" dev "); + q = p; + for (;*p != ' ' && *p; p++) + ; + *p = '\0'; + return xstrdup(q); +#else + return NULL; +#endif +} + /* This finds the first interface which is up and is not the loopback * interface or one of the interface types listed in bad_interface_names. */ static char *get_first_interface(void) { @@ -123,9 +194,13 @@ static char *get_first_interface(void) {
void options_set_defaults() { char *s; + + if (!options.interface) + options.interface = get_interface_for_default_ipv4_route(); /* Should go through the list of interfaces, and find the first one which * is up and is not lo or dummy*. */ - options.interface = get_first_interface(); + if (!options.interface) + options.interface = get_first_interface(); if (!options.interface) options.interface = "eth0";
Hi Shawn,
Thanks for this. Unfortunately, it doesn't work:
r = read(fds[1], &buf, sizeof(buf));
fds[1] is the write end of the pipe, so reading from it doesn't work.
This highlights another problem:
fprintf(stderr, "get_interface_for_default_ipv4_route: read() failed: %s, continuing...", strerror(r));
vs.
"On error, -1 is returned, and errno is set appropriately."
Paul
On 11/06/18 02:40, Shawn Landden wrote:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=644998
options.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/options.c b/options.c index a075357..efff2c7 100644 --- a/options.c +++ b/options.c @@ -6,8 +6,13 @@
#include "config.h"
+#ifdef __linux__ +#define _GNU_SOURCE +#endif
- #include <sys/types.h>
+#include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -90,6 +95,72 @@ static int is_bad_interface_name(char *i) { return 0; }
+/* none of these errors are expected, so I think it is OK to print them */ +static char *get_interface_for_default_ipv4_route(void) { +#ifdef __linux__
- pid_t pid;
- int fds[2];
- int r;
- char buf[4096];
- char *p, *q;
- r = pipe2(fds, O_CLOEXEC);
- if (r < 0) {
fprintf(stderr, "get_interface_for_default_ipv4_route: pipe() failed: %s, continuing...", strerror(r));
return NULL;
- }
- pid = fork();
- if (pid < 0) {
fprintf(stderr, "get_interface_for_default_ipv4_route: fork() failed: %s, continuing...", strerror(r));
return NULL;
- } else if (pid == 0) {
/* child */
r = dup2(fds[0], STDOUT_FILENO);
if (r < 0) {
char buf[1] = {'\n'};
/* we have to write something as the other end is expecting something */
r = write(fds[0], &buf, sizeof(buf));
_exit(EXIT_FAILURE);
}
execlp("ip", /* add "-6", here to make default IPv6 route */ "route", NULL);
char buf[1] = {'\n'};
/* we have to write something as the other end is expecting something */
r = write(fds[0], &buf, sizeof(buf));
_exit(EXIT_FAILURE);
- }
- /* parent */
- close(fds[1]);
- r = read(fds[1], &buf, sizeof(buf));
- if (r < 0) {
fprintf(stderr, "get_interface_for_default_ipv4_route: read() failed: %s, continuing...", strerror(r));
return NULL;
- }
- p = strstr((char *)&buf, "default via ");
- if (!p)
return NULL;
- p += strlen("default via ");
- q = p;
- for (;*p != '\n' && *p; p++)
;
- *p = '\0';
- p = strstr(q, " dev ");
- if (!p)
return NULL;
- p += strlen(" dev ");
- q = p;
- for (;*p != ' ' && *p; p++)
;
- *p = '\0';
- return xstrdup(q);
+#else
- return NULL;
+#endif +}
- /* This finds the first interface which is up and is not the loopback
static char *get_first_interface(void) {
- interface or one of the interface types listed in bad_interface_names. */
@@ -123,9 +194,13 @@ static char *get_first_interface(void) {
void options_set_defaults() { char *s;
- if (!options.interface)
options.interface = get_interface_for_default_ipv4_route(); /* Should go through the list of interfaces, and find the first one which * is up and is not lo or dummy*. */
- options.interface = get_first_interface();
- if (!options.interface)
options.interface = get_first_interface(); if (!options.interface) options.interface = "eth0";
On Mon, Jun 11, 2018 at 2:19 AM Paul Warren pdw@ex-parrot.com wrote:
Hi Shawn,
Thanks for this. Unfortunately, it doesn't work:
r = read(fds[1], &buf, sizeof(buf));
Ahh, on my Ubuntu machine optimization led the close() on the wrong fd to
run _after_ the read(), so it worked. But thankfully you caught it (this is why we test!).
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=644998
IPv4 detection first, cause iftop does not work with v4tunnel --- options.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/options.c b/options.c index a075357..1363597 100644 --- a/options.c +++ b/options.c @@ -6,8 +6,14 @@
#include "config.h"
+#ifdef __linux__ +#define _GNU_SOURCE +#endif + #include <sys/types.h>
+#include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -90,6 +96,76 @@ static int is_bad_interface_name(char *i) { return 0; }
+/* none of these errors are expected, so I think it is OK to print them */ +static char *get_interface_for_default_route(int ipv6) { +#ifdef __linux__ + pid_t pid; + int fds[2]; + int r; + char buf[4096]; + char *p, *q; + + r = pipe2(fds, O_CLOEXEC); + if (r < 0) { + (void)fprintf(stderr, "%s: %s() failed: %s, continuing...", __PRETTY_FUNCTION__, "pipe2", strerror(errno)); + return NULL; + } + pid = fork(); + if (pid < 0) { + (void)fprintf(stderr, "%s: %s() failed: %s, continuing...", __PRETTY_FUNCTION__, "fork", strerror(errno)); + return NULL; + } else if (pid == 0) { + /* child */ + r = dup2(fds[1], STDOUT_FILENO); + if (r < 0) { + char buf[1] = {'\n'}; + + /* we have to write something as the other end is expecting something */ + r = write(fds[1], &buf, sizeof(buf)); + _exit(EXIT_FAILURE); + } + + if (ipv6) + execlp("ip", "ip", "-6", "route", NULL); + else + execlp("ip", "ip", "route", NULL); + char buf[1] = {'\n'}; + + /* we have to write something as the other end is expecting something */ + r = write(fds[1], &buf, sizeof(buf)); + _exit(EXIT_FAILURE); + } + /* parent */ + close(fds[1]); + r = read(fds[0], &buf, sizeof(buf)); + if (r < 0) { + (void)fprintf(stderr, "%s: %s() failed: %s, continuing...", __PRETTY_FUNCTION__, "read", strerror(errno)); + return NULL; + } + + p = strstr((char *)&buf, "default via "); + if (!p) + return NULL; + p += strlen("default via "); + q = p; + for (;*p != '\n' && *p; p++) + ; + *p = '\0'; + p = strstr(q, " dev "); + if (!p) + return NULL; + p += strlen(" dev "); + q = p; + for (;*p != ' ' && *p; p++) + ; + *p = '\0'; + return xstrdup(q); +#else + return NULL; +#endif +} + /* This finds the first interface which is up and is not the loopback * interface or one of the interface types listed in bad_interface_names. */ static char *get_first_interface(void) { @@ -123,9 +199,16 @@ static char *get_first_interface(void) {
void options_set_defaults() { char *s; + + if (!options.interface) /* IPv4. Must come first because iftop does not work with v4tunnels. + https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=901283 */ + options.interface = get_interface_for_default_route(0); + if (!options.interface) /* IPv6*/ + options.interface = get_interface_for_default_route(1); /* Should go through the list of interfaces, and find the first one which * is up and is not lo or dummy*. */ - options.interface = get_first_interface(); + if (!options.interface) + options.interface = get_first_interface(); if (!options.interface) options.interface = "eth0";
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=644998
IPv4 detection first, cause iftop does not work with v4tunnel
v3: close both fds after they are used --- options.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/options.c b/options.c index a075357..089d2b2 100644 --- a/options.c +++ b/options.c @@ -6,8 +6,14 @@
#include "config.h"
+#ifdef __linux__ +#define _GNU_SOURCE +#endif + #include <sys/types.h>
+#include <errno.h> +#include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -90,6 +96,76 @@ static int is_bad_interface_name(char *i) { return 0; }
+/* none of these errors are expected, so I think it is OK to print them */ +static char *get_interface_for_default_route(int ipv6) { +#ifdef __linux__ + pid_t pid; + int fds[2]; + int r; + char buf[4096]; + char *p, *q; + + r = pipe2(fds, O_CLOEXEC); + if (r < 0) { + (void)fprintf(stderr, "%s: %s() failed: %s, continuing...", __PRETTY_FUNCTION__, "pipe2", strerror(errno)); + return NULL; + } + pid = fork(); + if (pid < 0) { + (void)fprintf(stderr, "%s: %s() failed: %s, continuing...", __PRETTY_FUNCTION__, "fork", strerror(errno)); + return NULL; + } else if (pid == 0) { + /* child */ + r = dup2(fds[1], STDOUT_FILENO); + if (r < 0) { + char buf[1] = {'\n'}; + + /* we have to write something as the other end is expecting something */ + r = write(fds[1], &buf, sizeof(buf)); + _exit(EXIT_FAILURE); + } + + if (ipv6) + execlp("ip", "ip", "-6", "route", NULL); + else + execlp("ip", "ip", "route", NULL); + char buf[1] = {'\n'}; + + /* we have to write something as the other end is expecting something */ + r = write(fds[1], &buf, sizeof(buf)); + _exit(EXIT_FAILURE); + } + /* parent */ + close(fds[1]); + r = read(fds[0], &buf, sizeof(buf)); + close(fds[0]); + if (r < 0) { + (void)fprintf(stderr, "%s: %s() failed: %s, continuing...", __PRETTY_FUNCTION__, "read", strerror(errno)); + return NULL; + } + + p = strstr((char *)&buf, "default via "); + if (!p) + return NULL; + p += strlen("default via "); + q = p; + for (;*p != '\n' && *p; p++) + ; + *p = '\0'; + p = strstr(q, " dev "); + if (!p) + return NULL; + p += strlen(" dev "); + q = p; + for (;*p != ' ' && *p; p++) + ; + *p = '\0'; + return xstrdup(q); +#else + return NULL; +#endif +} + /* This finds the first interface which is up and is not the loopback * interface or one of the interface types listed in bad_interface_names. */ static char *get_first_interface(void) { @@ -123,9 +199,16 @@ static char *get_first_interface(void) {
void options_set_defaults() { char *s; + + if (!options.interface) /* IPv4. Must come first because iftop does not work with v4tunnels. + https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=901283 */ + options.interface = get_interface_for_default_route(0); + if (!options.interface) /* IPv6*/ + options.interface = get_interface_for_default_route(1); /* Should go through the list of interfaces, and find the first one which * is up and is not lo or dummy*. */ - options.interface = get_first_interface(); + if (!options.interface) + options.interface = get_first_interface(); if (!options.interface) options.interface = "eth0";