$ git clone https://socialnetwork.ion.nu/socialnetwork.git
commit c76b97a476bf6899bd775e298f9ed5fad650304e
Author: Alicia <...>
Date:   Fri Jun 9 15:53:49 2017 +0000

    Switched from struct sockaddr to struct sockaddr_storage, which is large enough to hold IPv6 addresses.

diff --git a/peer.c b/peer.c
index 7d02247..dc3b50a 100644
--- a/peer.c
+++ b/peer.c
@@ -81,7 +81,7 @@ static void sendpeers(struct peer* peer, void* x, unsigned int len)
 struct peeritem
 {
   uint16_t addrlen;
-  struct sockaddr addr;
+  struct sockaddr_storage addr;
   uint16_t peercount;
 };
 static void getpeers(struct peer* peer, void* data, unsigned int len)
@@ -95,7 +95,7 @@ static void getpeers(struct peer* peer, void* data, unsigned int len)
   {
     memcpy(&addrlen, data, sizeof(addrlen));
     if(len<sizeof(addrlen)+addrlen+sizeof(pcount)){break;}
-    if(addrlen<=sizeof(struct sockaddr))
+    if(addrlen<=sizeof(struct sockaddr_storage))
     {
       ++pcount;
       peers=realloc(peers, sizeof(struct peeritem)*pcount);
@@ -128,7 +128,7 @@ printf("We now have %u peers\n", peercount);
 struct findpeer_request
 {
   unsigned char id[ID_SIZE];
-  struct sockaddr addr;
+  struct sockaddr_storage addr;
   uint16_t addrlen;
   time_t timestamp;
 };
@@ -144,7 +144,7 @@ printf("Got findpeer request for '"PEERFMT"'\n", PEERARG(id));
   memcpy(&ttl, data+ID_SIZE, sizeof(ttl));
   if(!ttl){return;}
   --ttl;
-  struct sockaddr addr;
+  struct sockaddr_storage addr;
   uint16_t addrlen;
   if(len>ID_SIZE+sizeof(ttl)+sizeof(addrlen))
   { // Has address already
@@ -350,7 +350,7 @@ struct peer* peer_get(struct udpstream* stream)
   return peer_new(stream, 1);
 }
 
-struct peer* peer_new_unique(int sock, struct sockaddr* addr, socklen_t addrlen)
+struct peer* peer_new_unique(int sock, struct sockaddr_storage* addr, socklen_t addrlen)
 {
   unsigned int i;
   // Make sure we're not already connected to this peer
@@ -376,12 +376,20 @@ void peer_bootstrap(int sock, const char* peerlist)
     entry=(end[0]?&end[1]:0);
     char* port;
     if((port=strchr(peer, '\r'))){port[0]=0;}
-    if(!(port=strchr(peer, ':'))){continue;} // Bogus entry
+    if(!(port=strrchr(peer, ':'))){continue;} // Bogus entry
     port[0]=0;
+    // Strip [ and ] (IPv6)
+    char* host=peer;
+    if(host[0]=='[')
+    {
+      host=&host[1];
+      char* end=strchr(host, ']');
+      if(end){end[0]=0;}
+    }
     struct addrinfo* ai;
-    if(!getaddrinfo(peer, &port[1], 0, &ai))
+    if(!getaddrinfo(host, &port[1], 0, &ai))
     {
-      peer_new_unique(sock, ai->ai_addr, ai->ai_addrlen);
+      peer_new_unique(sock, (struct sockaddr_storage*)ai->ai_addr, ai->ai_addrlen);
       freeaddrinfo(ai);
     }
   }
@@ -514,15 +522,11 @@ void peer_exportpeers(const char* path)
   for(i=0; i<peercount; ++i)
   {
     if(!peers[i]->handshake){continue;} // Skip bad peers
-    switch(peers[i]->addr.sa_family)
-    {
-    case AF_INET:
-      {
-      struct sockaddr_in* addr=(struct sockaddr_in*)&peers[i]->addr;
-      unsigned char* ip=(unsigned char*)&addr->sin_addr.s_addr;
-      dprintf(f, "%hhu.%hhu.%hhu.%hhu:%hu\n", ip[0], ip[1], ip[2], ip[3], ntohs(addr->sin_port));
-      }
-    }
+    char addr[INET6_ADDRSTRLEN];
+    char port[64];
+    if(getnameinfo((struct sockaddr*)&peers[i]->addr, peers[i]->addrlen, addr, INET6_ADDRSTRLEN, port, 64, NI_NUMERICHOST|NI_NUMERICSERV|NI_DGRAM)){continue;}
+    const char* fmt=((peers[i]->addr.ss_family==AF_INET6)?"[%s]:%s":"%s:%s");
+    dprintf(f, fmt, addr, port);
   }
   close(f);
 }
diff --git a/peer.h b/peer.h
index b0b85b4..5b316b0 100644
--- a/peer.h
+++ b/peer.h
@@ -28,7 +28,7 @@ struct peer
   uint8_t cmdlength;
   char* cmdname;
   int32_t datalength;
-  struct sockaddr addr;
+  struct sockaddr_storage addr;
   socklen_t addrlen;
   unsigned char id[ID_SIZE]; // SHA2-256 sum of public key (binary)
   gnutls_x509_crt_t cert;
@@ -44,7 +44,7 @@ extern void peer_registercmd(const char* name, void(*callback)(struct peer*,void
 extern void peer_init(const char* keypath);
 extern struct peer* peer_new(struct udpstream* stream, char server);
 extern struct peer* peer_get(struct udpstream* stream);
-extern struct peer* peer_new_unique(int sock, struct sockaddr* addr, socklen_t addrlen);
+extern struct peer* peer_new_unique(int sock, struct sockaddr_storage* addr, socklen_t addrlen);
 extern void peer_bootstrap(int sock, const char* peerlist);
 extern void peer_handlesocket(int sock); // Incoming data
 extern void peer_sendcmd(struct peer* peer, const char* cmd, const void* data, uint32_t len);
diff --git a/udpstream.c b/udpstream.c
index ba57da5..86cedf3 100644
--- a/udpstream.c
+++ b/udpstream.c
@@ -49,7 +49,7 @@ struct packet
 struct udpstream
 {
   int sock;
-  struct sockaddr addr;
+  struct sockaddr_storage addr;
   socklen_t addrlen;
   uint16_t inseq;
   uint16_t outseq;
@@ -67,7 +67,7 @@ struct udpstream
 static struct udpstream** streams=0;
 static unsigned int streamcount=0;
 
-static struct udpstream* stream_new(int sock, struct sockaddr* addr, socklen_t addrlen)
+static struct udpstream* stream_new(int sock, struct sockaddr_storage* addr, socklen_t addrlen)
 {
   struct udpstream* stream=malloc(sizeof(struct udpstream));
   stream->sock=sock;
@@ -89,7 +89,7 @@ static struct udpstream* stream_new(int sock, struct sockaddr* addr, socklen_t a
   return stream;
 }
 
-struct udpstream* udpstream_find(struct sockaddr* addr, socklen_t addrlen)
+struct udpstream* udpstream_find(struct sockaddr_storage* addr, socklen_t addrlen)
 {
   unsigned int i;
   for(i=0; i<streamcount; ++i)
@@ -110,7 +110,7 @@ static ssize_t stream_send(struct udpstream* stream, uint8_t type, uint16_t seq,
   memcpy(packet+sizeof(uint32_t), &seq, sizeof(uint16_t));
   memcpy(packet+sizeof(uint32_t)+sizeof(uint16_t), &type, sizeof(uint8_t));
   memcpy(packet+HEADERSIZE, buf, size);
-  return sendto(stream->sock, packet, HEADERSIZE+size, 0, &stream->addr, stream->addrlen);
+  return sendto(stream->sock, packet, HEADERSIZE+size, 0, (struct sockaddr*)&stream->addr, stream->addrlen);
 }
 
 static void udpstream_requestresend(struct udpstream* stream, uint16_t seq)
@@ -163,7 +163,7 @@ static void stream_free(struct udpstream* stream)
   }
 }
 
-struct udpstream* udpstream_new(int sock, struct sockaddr* addr, socklen_t addrlen)
+struct udpstream* udpstream_new(int sock, struct sockaddr_storage* addr, socklen_t addrlen)
 {
   struct udpstream* stream=stream_new(sock, addr, addrlen);
   stream->state=STATE_INIT; // If we're creating the stream we're the ones initializing it
@@ -175,9 +175,9 @@ void udpstream_readsocket(int sock)
 {
   time_t now=time(0);
   char buf[1024];
-  struct sockaddr addr;
+  struct sockaddr_storage addr;
   socklen_t addrlen=sizeof(addr);
-  ssize_t len=recvfrom(sock, buf, 1024, 0, &addr, &addrlen);
+  ssize_t len=recvfrom(sock, buf, 1024, 0, (struct sockaddr*)&addr, &addrlen);
   struct udpstream* stream=udpstream_find(&addr, addrlen);
   if(!stream){stream=stream_new(sock, &addr, addrlen);}
   stream->buflen+=len;
@@ -370,7 +370,7 @@ ssize_t udpstream_write(struct udpstream* stream, const void* buf, size_t size)
   return size;
 }
 
-void udpstream_getaddr(struct udpstream* stream, struct sockaddr* addr, socklen_t* addrlen)
+void udpstream_getaddr(struct udpstream* stream, struct sockaddr_storage* addr, socklen_t* addrlen)
 {
   if(*addrlen>stream->addrlen){*addrlen=stream->addrlen;}
   memcpy(addr, &stream->addr, *addrlen);
diff --git a/udpstream.h b/udpstream.h
index ccb2184..b1c4802 100644
--- a/udpstream.h
+++ b/udpstream.h
@@ -21,9 +21,9 @@
 struct udpstream;
 
 // Create a new stream on the given socket that sends and receives to/from the given address
-extern struct udpstream* udpstream_new(int sock, struct sockaddr* addr, socklen_t addrlen);
+extern struct udpstream* udpstream_new(int sock, struct sockaddr_storage* addr, socklen_t addrlen);
 
-extern struct udpstream* udpstream_find(struct sockaddr* addr, socklen_t addrlen);
+extern struct udpstream* udpstream_find(struct sockaddr_storage* addr, socklen_t addrlen);
 
 extern void udpstream_readsocket(int sock);
 
@@ -35,7 +35,7 @@ extern ssize_t udpstream_read(struct udpstream* stream, void* buf, size_t size);
 extern ssize_t udpstream_write(struct udpstream* stream, const void* buf, size_t size);
 
 // Get the network address of a stream's peer (useful for UDP-punchthrough)
-extern void udpstream_getaddr(struct udpstream* stream, struct sockaddr* addr, socklen_t* addrlen);
+extern void udpstream_getaddr(struct udpstream* stream, struct sockaddr_storage* addr, socklen_t* addrlen);
 
 extern int udpstream_getsocket(struct udpstream* stream);
 
diff --git a/udptest.c b/udptest.c
index be25c6f..68f7a96 100644
--- a/udptest.c
+++ b/udptest.c
@@ -31,7 +31,7 @@ int main(int argc, char** argv)
   {
     struct addrinfo* ai;
     getaddrinfo(argv[1], argv[2], 0, &ai);
-    stream=udpstream_new(sock, ai->ai_addr, ai->ai_addrlen);
+    stream=udpstream_new(sock, (struct sockaddr_storage*)ai->ai_addr, ai->ai_addrlen);
     freeaddrinfo(ai);
   }
   else if(argc>1)
@@ -60,13 +60,14 @@ int main(int argc, char** argv)
       struct udpstream* rstream;
       while((rstream=udpstream_poll()))
       {
-        struct sockaddr_in addr;
+        struct sockaddr_storage addr;
         socklen_t addrlen=sizeof(addr);
-        udpstream_getaddr(rstream, (struct sockaddr*)&addr, &addrlen);
-        if(addr.sin_family==AF_INET)
+        udpstream_getaddr(rstream, &addr, &addrlen);
+        if(addr.ss_family==AF_INET)
         {
-          uint32_t ip=addr.sin_addr.s_addr;
-          printf("From: %u.%u.%u.%u:%hu:\n", ip%0x100, (ip/0x100)%0x100, (ip/0x10000)%0x100, ip/0x1000000, ntohs(addr.sin_port));
+          uint32_t ip=((struct sockaddr_in*)&addr)->sin_addr.s_addr;
+          uint16_t port=((struct sockaddr_in*)&addr)->sin_port;
+          printf("From: %u.%u.%u.%u:%hu:\n", ip%0x100, (ip/0x100)%0x100, (ip/0x10000)%0x100, ip/0x1000000, ntohs(port));
         }
         ssize_t len=udpstream_read(rstream, buf, 1024);
         if(len<1){udpstream_close(rstream); if(stream==rstream){stream=0;} continue;}