blob: 9f6bb882b26845b51069c202372ba49275892129 [file] [log] [blame]
Deokgyu Yang2c7e86b2020-04-28 10:56:11 +09001/*
2 * network.c:
3 * Part of wiringPiD
4 * Copyright (c) 2012-2017 Gordon Henderson
5 ***********************************************************************
6 * This file is part of wiringPi:
7 * https://projects.drogon.net/raspberry-pi/wiringpi/
8 *
9 * wiringPi is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * wiringPi is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
21 ***********************************************************************
22 */
23
24#include <sys/socket.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <string.h>
31#include <stdarg.h>
32#include <malloc.h>
33
34#include <fcntl.h>
35#include <crypt.h>
36
37#include "network.h"
38
39#define TRUE (1==1)
40#define FALSE (!TRUE)
41
42// Local data
43
44#define SALT_LEN 16
45
46static char salt [SALT_LEN + 1] ;
47static char *returnedHash = NULL ;
48static int serverFd = -1 ;
49
50// Union for the server Socket Address
51
52static union
53{
54 struct sockaddr_in sin ;
55 struct sockaddr_in6 sin6 ;
56} serverSockAddr ;
57
58// and client address
59
60static union
61{
62 struct sockaddr_in sin ;
63 struct sockaddr_in6 sin6 ;
64} clientSockAddr ;
65
66
67/*
68 * getClientIP:
69 * Returns a pointer to a static string containing the clients IP address
70 *********************************************************************************
71 */
72
73char *getClientIP (void)
74{
75 char buf [INET6_ADDRSTRLEN] ;
76 static char ipAddress [1024] ;
77
78 if (clientSockAddr.sin.sin_family == AF_INET) // IPv4
79 {
80 if (snprintf (ipAddress, 1024, "IPv4: %s",
81 inet_ntop (clientSockAddr.sin.sin_family, (void *)&clientSockAddr.sin.sin_addr, buf, sizeof (buf))) == 1024)
82 strcpy (ipAddress, "Too long") ;
83 }
84 else // IPv6
85 {
86 if (clientSockAddr.sin.sin_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&clientSockAddr.sin6.sin6_addr))
87 {
88 if (snprintf (ipAddress, 1024, "IPv4in6: %s",
89 inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
90 strcpy (ipAddress, "Too long") ;
91 }
92 else
93 {
94 if (snprintf (ipAddress, 1024, "IPv6: %s",
95 inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
96 strcpy (ipAddress, "Too long") ;
97 }
98 }
99
100 return ipAddress ;
101}
102
103
104
105/*
106 * clientPstr: clientPrintf:
107 * Print over a network socket
108 *********************************************************************************
109 */
110
111static int clientPstr (int fd, char *s)
112{
113 int len = strlen (s) ;
114 return (write (fd, s, len) == len) ? 0 : -1 ;
115}
116
117static int clientPrintf (const int fd, const char *message, ...)
118{
119 va_list argp ;
120 char buffer [1024] ;
121
122 va_start (argp, message) ;
123 vsnprintf (buffer, 1023, message, argp) ;
124 va_end (argp) ;
125
126 return clientPstr (fd, buffer) ;
127}
128
129
130/*
131 * sendGreeting:
132 * Send some text to the client device
133 *********************************************************************************
134 */
135
136int sendGreeting (int clientFd)
137{
138 if (clientPrintf (clientFd, "200 Welcome to wiringPiD - http://wiringpi.com/\n") < 0)
139 return -1 ;
140
141 return clientPrintf (clientFd, "200 Connecting from: %s\n", getClientIP ()) ;
142}
143
144
145/*
146 * getSalt:
147 * Create a random 'salt' value for the password encryption process
148 *********************************************************************************
149 */
150
151static int getSalt (char drySalt [])
152{
153 static const char *seaDog = "abcdefghijklmnopqrstuvwxyz"
154 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
155 "0123456789/." ;
156
157 unsigned char wetSalt [SALT_LEN] ;
158 int i, fd ;
159
160 if ((fd = open ("/dev/urandom", O_RDONLY)) < 0)
161 return fd ;
162
163 if (read (fd, wetSalt, SALT_LEN) != SALT_LEN)
164 return -1 ;
165
166 close (fd) ;
167
168 for (i = 0 ; i < SALT_LEN ; ++i)
169 drySalt [i] = seaDog [wetSalt [i] & 63] ;
170
171 drySalt [SALT_LEN] = 0 ;
172
173 return 0 ;
174}
175
176
177/*
178 * sendChallenge:
179 * Create and send our salt (aka nonce) to the remote device
180 *********************************************************************************
181 */
182
183int sendChallenge (int clientFd)
184{
185 if (getSalt (salt) < 0)
186 return -1 ;
187
188 return clientPrintf (clientFd, "Challenge %s\n", salt) ;
189}
190
191
192/*
193 * getResponse:
194 * Read the encrypted password from the remote device.
195 *********************************************************************************
196 */
197
198
199int getResponse (int clientFd)
200{
201 char reply [1024] ;
202 int len ;
203
204// Being sort of lazy about this. I'm expecting an SHA-512 hash back and these
205// are exactly 86 characters long, so no reason not to, I guess...
206
207 len = 86 ;
208
209 if (setsockopt (clientFd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0)
210 return -1 ;
211
212 len = recv (clientFd, reply, 86, 0) ;
213 if (len != 86)
214 return -1 ;
215
216 reply [len] = 0 ;
217
218 if ((returnedHash = malloc (len + 1)) == NULL)
219 return -1 ;
220
221 strcpy (returnedHash, reply) ;
222
223 return 0 ;
224}
225
226
227/*
228 * passwordMatch:
229 * See if there's a match. If not, we simply dump them.
230 *********************************************************************************
231 */
232
233int passwordMatch (const char *password)
234{
235 char *encrypted ;
236 char salted [1024] ;
237
238 sprintf (salted, "$6$%s$", salt) ;
239
240 encrypted = crypt (password, salted) ;
241
242// 20: $6$ then 16 characters of salt, then $
243// 86 is the length of an SHA-512 hash
244
245 return strncmp (encrypted + 20, returnedHash, 86) == 0 ;
246}
247
248
249/*
250 * setupServer:
251 * Do what's needed to create a local server socket instance that can listen
252 * on both IPv4 and IPv6 interfaces.
253 *********************************************************************************
254 */
255
256int setupServer (int serverPort)
257{
258 socklen_t clientSockAddrSize = sizeof (clientSockAddr) ;
259
260 int on = 1 ;
261 int family ;
262 socklen_t serverSockAddrSize ;
263 int clientFd ;
264
265// Try to create an IPv6 socket
266
267 serverFd = socket (PF_INET6, SOCK_STREAM, 0) ;
268
269// If it didn't work, then fall-back to IPv4.
270
271 if (serverFd < 0)
272 {
273 if ((serverFd = socket (PF_INET, SOCK_STREAM, 0)) < 0)
274 return -1 ;
275
276 family = AF_INET ;
277 serverSockAddrSize = sizeof (struct sockaddr_in) ;
278 }
279 else // We got an IPv6 socket
280 {
281 family = AF_INET6 ;
282 serverSockAddrSize = sizeof (struct sockaddr_in6) ;
283 }
284
285 if (setsockopt (serverFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
286 return -1 ;
287
288// Setup the servers socket address - cope with IPv4 and v6.
289
290 memset (&serverSockAddr, 0, sizeof (serverSockAddr)) ;
291 switch (family)
292 {
293 case AF_INET:
294 serverSockAddr.sin.sin_family = AF_INET ;
295 serverSockAddr.sin.sin_addr.s_addr = htonl (INADDR_ANY) ;
296 serverSockAddr.sin.sin_port = htons (serverPort) ;
297 break;
298
299 case AF_INET6:
300 serverSockAddr.sin6.sin6_family = AF_INET6 ;
301 serverSockAddr.sin6.sin6_addr = in6addr_any ;
302 serverSockAddr.sin6.sin6_port = htons (serverPort) ;
303 }
304
305// Bind, listen and accept
306
307 if (bind (serverFd, (struct sockaddr *)&serverSockAddr, serverSockAddrSize) < 0)
308 return -1 ;
309
310 if (listen (serverFd, 4) < 0) // Really only going to talk to one client at a time...
311 return -1 ;
312
313 if ((clientFd = accept (serverFd, (struct sockaddr *)&clientSockAddr, &clientSockAddrSize)) < 0)
314 return -1 ;
315
316 return clientFd ;
317}
318
319
320/*
321 * closeServer:
322 *********************************************************************************
323 */
324
325void closeServer (int clientFd)
326{
327 if (serverFd != -1) close (serverFd) ;
328 if (clientFd != -1) close (clientFd) ;
329 serverFd = clientFd = -1 ;
330}