diff --git a/nbase/nbase_misc.c b/nbase/nbase_misc.c index 14c6a27d2..5faae5d4e 100644 --- a/nbase/nbase_misc.c +++ b/nbase/nbase_misc.c @@ -284,6 +284,20 @@ int block_socket(int sd) { /* Use the SO_BINDTODEVICE sockopt to bind with a specific interface (Linux only). Pass NULL or an empty string to remove device binding. */ int socket_bindtodevice(int sd, const char *device) { + char padded[sizeof(int)]; + + /* In Linux 2.6.20 and earlier, there is a bug in SO_BINDTODEVICE that causes + EINVAL to be returned if the optlen < sizeof(int); this happens for example + with the interface names "" and "lo". Pad the string with null characters + so it is above this limit if necessary. + http://article.gmane.org/gmane.linux.network/71887 + http://article.gmane.org/gmane.linux.network/72216 */ + if (strlen(device) + 1 < sizeof(padded)) { + /* We rely on strncpy padding with nulls here. */ + strncpy(padded, device, sizeof(padded)); + device = padded; + } + #ifdef SO_BINDTODEVICE /* Linux-specific sockopt asking to use a specific interface. See socket(7). */ if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) < 0)