1 //
2 // Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
3 // Copyright 2018 Capitar IT Group BV <info@capitar.com>
4 //
5 // This software is supplied under the terms of the MIT License, a
6 // copy of which should be located in the distribution where this
7 // file was obtained (LICENSE.txt).  A copy of the license may also be
8 // found online at https://opensource.org/licenses/MIT.
9 //
10 
11 #include "core/nng_impl.h"
12 
13 #ifdef NNG_PLATFORM_POSIX
14 
15 #include <arpa/inet.h>
16 #include <fcntl.h>
17 #include <netinet/in.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <sys/un.h>
24 
25 size_t
nni_posix_nn2sockaddr(void * sa,const nni_sockaddr * na)26 nni_posix_nn2sockaddr(void *sa, const nni_sockaddr *na)
27 {
28 	struct sockaddr_in *         sin;
29 	struct sockaddr_in6 *        sin6;
30 	struct sockaddr_un *         spath;
31 	const nng_sockaddr_in *      nsin;
32 	const nng_sockaddr_in6 *     nsin6;
33 	const nng_sockaddr_path *    nspath;
34 	const nng_sockaddr_abstract *nsabs;
35 	size_t                       sz;
36 
37 	if ((sa == NULL) || (na == NULL)) {
38 		return (0);
39 	}
40 	switch (na->s_family) {
41 	case NNG_AF_INET:
42 		sin  = (void *) sa;
43 		nsin = &na->s_in;
44 		memset(sin, 0, sizeof(*sin));
45 		sin->sin_family      = PF_INET;
46 		sin->sin_port        = nsin->sa_port;
47 		sin->sin_addr.s_addr = nsin->sa_addr;
48 		return (sizeof(*sin));
49 
50 	case NNG_AF_INET6:
51 		sin6  = (void *) sa;
52 		nsin6 = &na->s_in6;
53 		memset(sin6, 0, sizeof(*sin6));
54 #ifdef SIN6_LEN
55 		sin6->sin6_len = sizeof(*sin6);
56 #endif
57 		sin6->sin6_family   = PF_INET6;
58 		sin6->sin6_port     = nsin6->sa_port;
59 		sin6->sin6_scope_id = nsin6->sa_scope;
60 		memcpy(sin6->sin6_addr.s6_addr, nsin6->sa_addr, 16);
61 		return (sizeof(*sin6));
62 
63 	case NNG_AF_IPC:
64 		spath  = (void *) sa;
65 		nspath = &na->s_ipc;
66 		memset(spath, 0, sizeof(*spath));
67 		// Make sure that the path fits!
68 		sz = sizeof(spath->sun_path);
69 		if (nni_strlcpy(spath->sun_path, nspath->sa_path, sz) >= sz) {
70 			return (0);
71 		}
72 		spath->sun_family = PF_UNIX;
73 		return (sizeof(*spath));
74 
75 	case NNG_AF_ABSTRACT:
76 		spath = (void *) sa;
77 		nsabs = &na->s_abstract;
78 		if (nsabs->sa_len >= sizeof (spath->sun_path)) {
79 			return (0);
80 		}
81 		memset(spath, 0, sizeof(*spath));
82 		spath->sun_family = PF_UNIX;
83 		spath->sun_path[0] = '\0'; // abstract starts with nul
84 
85 		// We support auto-bind with an empty string.  There is
86 		// a subtle caveat here, which is that we cannot bind to
87 		// the *empty* name.
88 		if (nsabs->sa_len == 0) {
89 			return (sizeof (sa_family_t)); // auto bind
90 		} else {
91 			memcpy(&spath->sun_path[1], nsabs->sa_name,
92 			    nsabs->sa_len);
93 			return (sizeof(sa_family_t) + 1 + nsabs->sa_len);
94 		}
95 	}
96 	return (0);
97 }
98 
99 int
nni_posix_sockaddr2nn(nni_sockaddr * na,const void * sa,size_t sz)100 nni_posix_sockaddr2nn(nni_sockaddr *na, const void *sa, size_t sz)
101 {
102 	const struct sockaddr_in * sin;
103 	const struct sockaddr_in6 *sin6;
104 	const struct sockaddr_un * spath;
105 	nng_sockaddr_in *          nsin;
106 	nng_sockaddr_in6 *         nsin6;
107 	nng_sockaddr_path *        nspath;
108 	nng_sockaddr_abstract *    nsabs;
109 
110 	if ((na == NULL) || (sa == NULL)) {
111 		return (-1);
112 	}
113 	switch (((struct sockaddr *) sa)->sa_family) {
114 	case AF_INET:
115 		if (sz < sizeof(*sin)) {
116 			return (-1);
117 		}
118 		sin             = (void *) sa;
119 		nsin            = &na->s_in;
120 		nsin->sa_family = NNG_AF_INET;
121 		nsin->sa_port   = sin->sin_port;
122 		nsin->sa_addr   = sin->sin_addr.s_addr;
123 		break;
124 	case AF_INET6:
125 		if (sz < sizeof(*sin6)) {
126 			return (-1);
127 		}
128 		sin6             = (void *) sa;
129 		nsin6            = &na->s_in6;
130 		nsin6->sa_family = NNG_AF_INET6;
131 		nsin6->sa_port   = sin6->sin6_port;
132 		nsin6->sa_scope  = sin6->sin6_scope_id;
133 		memcpy(nsin6->sa_addr, sin6->sin6_addr.s6_addr, 16);
134 		break;
135 	case AF_UNIX:
136 		// AF_UNIX can be NNG_AF_IPC, or NNG_AF_ABSTRACT.
137 		spath = (void *) sa;
138 		if ((sz < sizeof(sa_family_t)) || (sz > sizeof(*spath))) {
139 			return (-1);
140 		}
141 		// Now we need to look more closely.
142 		sz -= sizeof(sa_family_t);
143 		if (sz == 0) {
144 			// Unnamed socket.  These will be treated using
145 			// auto-bind if we actually listen to them, and
146 			// it is impossible to connect them.
147 			nsabs            = &na->s_abstract;
148 			nsabs->sa_family = NNG_AF_ABSTRACT;
149 			nsabs->sa_len    = 0;
150 		} else if (spath->sun_path[0] == 0) {
151 			nsabs            = &na->s_abstract;
152 			nsabs->sa_family = NNG_AF_ABSTRACT;
153 			nsabs->sa_len    = sz - 1;
154 			memcpy(nsabs->sa_name, &spath->sun_path[1], sz - 1);
155 		} else {
156                         nspath            = &na->s_ipc;
157 			nspath->sa_family = NNG_AF_IPC;
158 			nni_strlcpy(nspath->sa_path, spath->sun_path,
159 			    sizeof(nspath->sa_path));
160 		}
161 		break;
162 	default:
163 		// We should never see this - the OS should always be
164 		// specific about giving us either AF_INET or AF_INET6.
165 		// Other address families are not handled here.
166 		return (-1);
167 	}
168 	return (0);
169 }
170 
171 #endif // NNG_PLATFORM_POSIX
172