Add basic IPv6 support
authorFloris Bos <bos@je-eigen-domein.nl>
Fri, 17 Feb 2017 14:36:48 +0000 (15:36 +0100)
committerFloris Bos <bos@je-eigen-domein.nl>
Fri, 17 Feb 2017 14:36:48 +0000 (15:36 +0100)
Add IPv6 support to daemon and python library.
IPv6 was already supported by the C client library.

Currently there is no support for whitelisting IPv6 client
addresses implemented, so for now it reverts to listening
to IPv4 only when the -n <ip> option is specified.

Signed-off-by: Floris Bos <bos@je-eigen-domein.nl>
pigpio.c
pigpio.py

index 3bacc2041a97a352a06c4db018a286f7185b82ec..570a8a2164e9c74796788f95718f23a974d2de34 100644 (file)
--- a/pigpio.c
+++ b/pigpio.c
@@ -6972,12 +6972,18 @@ static void *pthSocketThreadHandler(void *fdC)
    return 0;
 }
 
-static int addrAllowed(uint32_t addr)
+static int addrAllowed(struct sockaddr *saddr)
 {
    int i;
+   uint32_t addr;
 
    if (!numSockNetAddr) return 1;
 
+   // FIXME: add IPv6 whitelisting support
+   if (saddr->sa_family != AF_INET) return 0;
+
+   addr = ((struct sockaddr_in *) saddr)->sin_addr.s_addr;
+
    for (i=0; i<numSockNetAddr; i++)
    {
       if (addr == sockNetAddr[i]) return 1;
@@ -6990,7 +6996,7 @@ static int addrAllowed(uint32_t addr)
 static void * pthSocketThread(void *x)
 {
    int fdC=0, c, *sock;
-   struct sockaddr_in client;
+   struct sockaddr_storage client;
    pthread_attr_t attr;
 
    if (pthread_attr_init(&attr))
@@ -7010,7 +7016,7 @@ static void * pthSocketThread(void *x)
 
    listen(fdSock, 100);
 
-   c = sizeof(struct sockaddr_in);
+   c = sizeof(client);
 
    /* don't start until DMA started */
 
@@ -7024,7 +7030,7 @@ static void * pthSocketThread(void *x)
 
       closeOrphanedNotifications(-1, fdC);
 
-      if (addrAllowed(client.sin_addr.s_addr))
+      if (addrAllowed((struct sockaddr *)&client))
       {
          sock = malloc(sizeof(int));
 
@@ -8003,6 +8009,7 @@ int initInitialise(void)
 {
    int rev, i, model;
    struct sockaddr_in server;
+   struct sockaddr_in6 server6;
    char * portStr;
    unsigned port;
    struct sched_param param;
@@ -8107,28 +8114,54 @@ int initInitialise(void)
 
    if (!(gpioCfg.ifFlags & PI_DISABLE_SOCK_IF))
    {
-      fdSock = socket(AF_INET , SOCK_STREAM , 0);
-
-      if (fdSock == -1)
-         SOFT_ERROR(PI_INIT_FAILED, "socket failed (%m)");
-
       portStr = getenv(PI_ENVPORT);
-
       if (portStr) port = atoi(portStr); else port = gpioCfg.socketPort;
 
-      server.sin_family = AF_INET;
-      if (gpioCfg.ifFlags & PI_LOCALHOST_SOCK_IF)
+      // Accept connections on IPv6, unless we have an IPv4-only whitelist
+      if (!numSockNetAddr)
       {
-         server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+         fdSock = socket(AF_INET6, SOCK_STREAM , 0);
+
+         if (fdSock != -1)
+         {
+            bzero((char *)&server6, sizeof(server6));
+            server6.sin6_family = AF_INET6;
+            if (gpioCfg.ifFlags & PI_LOCALHOST_SOCK_IF)
+            {
+               server6.sin6_addr = in6addr_loopback;
+            }
+            else
+            {
+               server6.sin6_addr = in6addr_any;
+            }
+            server6.sin6_port = htons(port);
+
+            if (bind(fdSock,(struct sockaddr *)&server6, sizeof(server6)) < 0)
+               SOFT_ERROR(PI_INIT_FAILED, "bind to port %d failed (%m)", port);
+         }
       }
-      else
+
+      if (numSockNetAddr || fdSock == -1)
       {
-         server.sin_addr.s_addr = htonl(INADDR_ANY);
-      }
-      server.sin_port = htons(port);
+         fdSock = socket(AF_INET , SOCK_STREAM , 0);
+
+         if (fdSock == -1)
+            SOFT_ERROR(PI_INIT_FAILED, "socket failed (%m)");
 
-      if (bind(fdSock,(struct sockaddr *)&server , sizeof(server)) < 0)
-         SOFT_ERROR(PI_INIT_FAILED, "bind to port %d failed (%m)", port);
+         server.sin_family = AF_INET;
+         if (gpioCfg.ifFlags & PI_LOCALHOST_SOCK_IF)
+         {
+            server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+         }
+         else
+         {
+            server.sin_addr.s_addr = htonl(INADDR_ANY);
+         }
+         server.sin_port = htons(port);
+
+         if (bind(fdSock,(struct sockaddr *)&server , sizeof(server)) < 0)
+            SOFT_ERROR(PI_INIT_FAILED, "bind to port %d failed (%m)", port);
+      }
 
       if (pthread_create(&pthSocket, &pthAttr, pthSocketThread, &i))
          SOFT_ERROR(PI_INIT_FAILED, "pthread_create socket failed (%m)");
index 4876ab18cd429ec47ef969eda8f8bd05ed5ebf67..65e0ac5a633eedcd51140fa37ab56ebea3aa45ba 100644 (file)
--- a/pigpio.py
+++ b/pigpio.py
@@ -1047,9 +1047,7 @@ class _callback_thread(threading.Thread):
       self.event_bits = 0
       self.callbacks = []
       self.events = []
-      self.sl.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-      self.sl.s.settimeout(None)
-      self.sl.s.connect((host, port))
+      self.sl.s = socket.create_connection((host, port), None)
       self.handle = _pigpio_command(self.sl, _PI_CMD_NOIB, 0, 0)
       self.go = True
       self.start()
@@ -4931,14 +4929,12 @@ class pi():
       self._host = host
       self._port = port
 
-      self.sl.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-      self.sl.s.settimeout(None)
+      try:
+         self.sl.s = socket.create_connection((host, port), None)
 
-      # Disable the Nagle algorithm.
-      self.sl.s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+         # Disable the Nagle algorithm.
+         self.sl.s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
 
-      try:
-         self.sl.s.connect((host, port))
          self._notify = _callback_thread(self.sl, host, port)
 
       except socket.error: