Statistics
| Branch: | Revision:

ddr4s / fw / wiringPi / wiringPiD / network.c @ 32:cadb9025f1e0

History | View | Annotate | Download (7.79 KB)

1
/*
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

    
46
static char salt [SALT_LEN + 1] ;
47
static char *returnedHash = NULL ;
48
static int serverFd = -1 ;
49

    
50
// Union for the server Socket Address
51

    
52
static union
53
{
54
  struct sockaddr_in  sin ;
55
  struct sockaddr_in6 sin6 ;
56
} serverSockAddr ; 
57

    
58
// and client address
59

    
60
static 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

    
73
char *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

    
111
static int clientPstr (int fd, char *s)
112
{
113
  int len = strlen (s) ;
114
  return (write (fd, s, len) == len) ? 0 : -1 ;
115
}
116

    
117
static 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

    
136
int 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

    
151
static 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

    
183
int 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

    
199
int 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

    
233
int 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

    
256
int 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

    
325
void closeServer (int clientFd)
326
{
327
  if (serverFd != -1) close (serverFd) ;
328
  if (clientFd != -1) close (clientFd) ;
329
  serverFd = clientFd = -1 ;
330
}