 pjnath/src/pjnath/ice_session.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 176 insertions(+)

diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
index 2a4125bc5..542acf7b4 100644
--- a/pjnath/src/pjnath/ice_session.c
+++ b/pjnath/src/pjnath/ice_session.c
@@ -29,6 +29,21 @@
 #include <pj/rand.h>
 #include <pj/string.h>
 
+#if defined(_WIN32) || defined(__APPLE__)
+/* TODO(sblin): find an alternative for these paltforms */
+#else
+/* The following headers are used to get DEPRECATED addresses
+ * as specified in RFC 2462 Section 5.5.4
+ * https://tools.ietf.org/html/rfc2462#section-5.5.4
+ */
+#include <arpa/inet.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+
 /* String names for candidate types */
 static const char *cand_type_names[] =
 {
@@ -703,6 +718,144 @@ static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice,
 #endif
 }
 
+/* retrieve invalid addresses and store it in a string */
+static PJ_DEF(void) get_invalid_addresses(char** addresses, size_t* size)
+{
+#if defined(_WIN32) || defined(__APPLE__)
+    // PJ_TODO("sblin: find alternative for WIN32 and APPLE");
+#else
+    struct {
+	struct nlmsghdr        nlmsg_info;
+	struct ifaddrmsg    ifaddrmsg_info;
+    } netlink_req;
+
+    int fd;
+
+    long pagesize = sysconf(_SC_PAGESIZE);
+
+    if (!pagesize)
+	pagesize = 4096; /* Assume pagesize is 4096 if sysconf() failed */
+
+    fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    if(fd < 0) {
+	perror("socket initialization error: abort");
+	return;
+    }
+
+    int rtn;
+
+    bzero(&netlink_req, sizeof(netlink_req));
+
+    netlink_req.nlmsg_info.nlmsg_len   = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+    netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+    netlink_req.nlmsg_info.nlmsg_type  = RTM_GETADDR;
+    netlink_req.nlmsg_info.nlmsg_pid   = getpid();
+
+    netlink_req.ifaddrmsg_info.ifa_family = AF_INET6;
+
+    rtn = send(fd, &netlink_req, netlink_req.nlmsg_info.nlmsg_len, 0);
+    if(rtn < 0) {
+	perror("send error: abort");
+	return;
+    }
+
+    char read_buffer[pagesize];
+    struct nlmsghdr *nlmsg_ptr;
+    int nlmsg_len;
+
+    size_t idx = 0;
+    /* Will store all deprecated addresses into a string */
+    char* deprecatedAddrs = malloc(256*sizeof(char)*PJ_INET6_ADDRSTRLEN);
+    if (!deprecatedAddrs) {
+	perror("malloc error: abort");
+	return;
+    }
+
+    while(1) {
+	int rtn;
+
+	bzero(read_buffer, pagesize);
+	rtn = recv(fd, read_buffer, pagesize, 0);
+	if(rtn < 0) {
+	    perror ("recv(): ");
+	    free(deprecatedAddrs);
+	    return;
+	}
+
+	nlmsg_ptr = (struct nlmsghdr *) read_buffer;
+	nlmsg_len = rtn;
+
+	if (nlmsg_len < sizeof (struct nlmsghdr)) {
+	    perror ("Received an incomplete netlink packet");
+	    free(deprecatedAddrs);
+	    return;
+	}
+
+	if (nlmsg_ptr->nlmsg_type == NLMSG_DONE)
+	    break;
+
+	for(; NLMSG_OK(nlmsg_ptr, nlmsg_len);
+	    nlmsg_ptr = NLMSG_NEXT(nlmsg_ptr, nlmsg_len))
+	{
+	    struct ifaddrmsg *ifaddrmsg_ptr;
+	    struct rtattr *rtattr_ptr;
+	    int ifaddrmsg_len;
+
+	    ifaddrmsg_ptr = (struct ifaddrmsg *) NLMSG_DATA(nlmsg_ptr);
+
+	    if (ifaddrmsg_ptr->ifa_flags & IFA_F_DEPRECATED ||
+		ifaddrmsg_ptr->ifa_flags & IFA_F_TENTATIVE)
+	    {
+		rtattr_ptr = (struct rtattr *) IFA_RTA(ifaddrmsg_ptr);
+		ifaddrmsg_len = IFA_PAYLOAD(nlmsg_ptr);
+
+		for(;RTA_OK(rtattr_ptr, ifaddrmsg_len);
+		    rtattr_ptr = RTA_NEXT(rtattr_ptr, ifaddrmsg_len))
+		{
+		    switch(rtattr_ptr->rta_type) {
+		    case IFA_ADDRESS:
+			/* Any 256 obsolete ips (should not happen), resize the array. */
+			if (idx > 0 && idx % 256 == 0) {
+			    char* newDeprecated = realloc(deprecatedAddrs,
+							  (idx + 256)*sizeof(char)*PJ_INET6_ADDRSTRLEN);
+			    if (newDeprecated == NULL) {
+				perror("realloc error: abort");
+				free(deprecatedAddrs);
+				return;
+			    }
+			    deprecatedAddrs = newDeprecated;
+			}
+			/* Store deprecated IP */
+			inet_ntop(ifaddrmsg_ptr->ifa_family,
+				  RTA_DATA(rtattr_ptr),
+				  &deprecatedAddrs[idx*PJ_INET6_ADDRSTRLEN],
+				  sizeof(char)*PJ_INET6_ADDRSTRLEN);
+			++idx;
+			break;
+		    default:
+			break;
+		    }
+		}
+	    }
+	}
+    }
+
+    close(fd);
+    *size = idx;
+    if (idx > 0) {
+	char *final = realloc(deprecatedAddrs,
+			      idx*sizeof(char)*PJ_INET6_ADDRSTRLEN);
+	if (final) {
+	    *addresses = final;
+	} else {
+	    perror("realloc error: abort");
+	    free(deprecatedAddrs);
+	}
+	} else {
+	    free(deprecatedAddrs);
+    }
+#endif
+}
 
 /*
  * Add ICE candidate
@@ -719,6 +872,29 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice,
 					 int addr_len,
 					 unsigned *p_cand_id)
 {
+    /**
+     * RFC 2466: an ip address can have the status DEPRECATED and SHOULD NOT
+     * be used by new by applications unless they already use it.
+     * So, we should ignore these addresses.
+     * Also, ips with the TENTATIVE state are not ready and SHOULD NOT be
+     * used for now. Ignore these addresses too.
+     */
+    char* deprecatedAddrs = NULL;
+    size_t size = 0;
+    get_invalid_addresses(&deprecatedAddrs, &size);
+    if (deprecatedAddrs != NULL) {
+	char tmpAddrStr[PJ_INET6_ADDRSTRLEN];
+	pj_sockaddr_print(addr, tmpAddrStr, sizeof(tmpAddrStr), 0);
+	for (int i = 0; i<size*PJ_INET6_ADDRSTRLEN; i+=PJ_INET6_ADDRSTRLEN) {
+	    if (!strncmp(tmpAddrStr, &deprecatedAddrs[i], PJ_INET6_ADDRSTRLEN)) {
+		free(deprecatedAddrs);
+		/* This address is considered as deprecated ignore it. */
+		return PJ_SUCCESS;
+	    }
+	}
+	free(deprecatedAddrs);
+    }
+
     pj_ice_sess_cand *lcand;
     pj_status_t status = PJ_SUCCESS;
     char address[PJ_INET6_ADDRSTRLEN];
