network.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. #include <sys/socket.h>
  24. #include <netinet/in.h>
  25. #include <arpa/inet.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <string.h>
  30. #include <stdarg.h>
  31. #include <malloc.h>
  32. #include <fcntl.h>
  33. #include <crypt.h>
  34. #include "network.h"
  35. #define TRUE (1==1)
  36. #define FALSE (!TRUE)
  37. // Local data
  38. #define SALT_LEN 16
  39. static char salt [SALT_LEN + 1] ;
  40. static char *returnedHash = NULL ;
  41. static int serverFd = -1 ;
  42. // Union for the server Socket Address
  43. static union
  44. {
  45. struct sockaddr_in sin ;
  46. struct sockaddr_in6 sin6 ;
  47. } serverSockAddr ;
  48. // and client address
  49. static union
  50. {
  51. struct sockaddr_in sin ;
  52. struct sockaddr_in6 sin6 ;
  53. } clientSockAddr ;
  54. /*
  55. * getClientIP:
  56. * Returns a pointer to a static string containing the clients IP address
  57. *********************************************************************************
  58. */
  59. char *getClientIP (void)
  60. {
  61. char buf [INET6_ADDRSTRLEN] ;
  62. static char ipAddress [1024] ;
  63. if (clientSockAddr.sin.sin_family == AF_INET) // IPv4
  64. {
  65. if (snprintf (ipAddress, 1024, "IPv4: %s",
  66. inet_ntop (clientSockAddr.sin.sin_family, (void *)&clientSockAddr.sin.sin_addr, buf, sizeof (buf))) == 1024)
  67. strcpy (ipAddress, "Too long") ;
  68. }
  69. else // IPv6
  70. {
  71. if (clientSockAddr.sin.sin_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&clientSockAddr.sin6.sin6_addr))
  72. {
  73. if (snprintf (ipAddress, 1024, "IPv4in6: %s",
  74. inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
  75. strcpy (ipAddress, "Too long") ;
  76. }
  77. else
  78. {
  79. if (snprintf (ipAddress, 1024, "IPv6: %s",
  80. inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024)
  81. strcpy (ipAddress, "Too long") ;
  82. }
  83. }
  84. return ipAddress ;
  85. }
  86. /*
  87. * clientPstr: clientPrintf:
  88. * Print over a network socket
  89. *********************************************************************************
  90. */
  91. static int clientPstr (int fd, char *s)
  92. {
  93. int len = strlen (s) ;
  94. return (write (fd, s, len) == len) ? 0 : -1 ;
  95. }
  96. static int clientPrintf (const int fd, const char *message, ...)
  97. {
  98. va_list argp ;
  99. char buffer [1024] ;
  100. va_start (argp, message) ;
  101. vsnprintf (buffer, 1023, message, argp) ;
  102. va_end (argp) ;
  103. return clientPstr (fd, buffer) ;
  104. }
  105. /*
  106. * sendGreeting:
  107. * Send some text to the client device
  108. *********************************************************************************
  109. */
  110. int sendGreeting (int clientFd)
  111. {
  112. if (clientPrintf (clientFd, "200 Welcome to wiringPiD - http://wiringpi.com/\n") < 0)
  113. return -1 ;
  114. return clientPrintf (clientFd, "200 Connecting from: %s\n", getClientIP ()) ;
  115. }
  116. /*
  117. * getSalt:
  118. * Create a random 'salt' value for the password encryption process
  119. *********************************************************************************
  120. */
  121. static int getSalt (char drySalt [])
  122. {
  123. static const char *seaDog = "abcdefghijklmnopqrstuvwxyz"
  124. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  125. "0123456789/." ;
  126. unsigned char wetSalt [SALT_LEN] ;
  127. int i, fd ;
  128. if ((fd = open ("/dev/urandom", O_RDONLY)) < 0)
  129. return fd ;
  130. if (read (fd, wetSalt, SALT_LEN) != SALT_LEN)
  131. return -1 ;
  132. close (fd) ;
  133. for (i = 0 ; i < SALT_LEN ; ++i)
  134. drySalt [i] = seaDog [wetSalt [i] & 63] ;
  135. drySalt [SALT_LEN] = 0 ;
  136. return 0 ;
  137. }
  138. /*
  139. * sendChallenge:
  140. * Create and send our salt (aka nonce) to the remote device
  141. *********************************************************************************
  142. */
  143. int sendChallenge (int clientFd)
  144. {
  145. if (getSalt (salt) < 0)
  146. return -1 ;
  147. return clientPrintf (clientFd, "Challenge %s\n", salt) ;
  148. }
  149. /*
  150. * getResponse:
  151. * Read the encrypted password from the remote device.
  152. *********************************************************************************
  153. */
  154. int getResponse (int clientFd)
  155. {
  156. char reply [1024] ;
  157. int len ;
  158. // Being sort of lazy about this. I'm expecting an SHA-512 hash back and these
  159. // are exactly 86 characters long, so no reason not to, I guess...
  160. len = 86 ;
  161. if (setsockopt (clientFd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0)
  162. return -1 ;
  163. len = recv (clientFd, reply, 86, 0) ;
  164. if (len != 86)
  165. return -1 ;
  166. reply [len] = 0 ;
  167. if ((returnedHash = malloc (len + 1)) == NULL)
  168. return -1 ;
  169. strcpy (returnedHash, reply) ;
  170. return 0 ;
  171. }
  172. /*
  173. * passwordMatch:
  174. * See if there's a match. If not, we simply dump them.
  175. *********************************************************************************
  176. */
  177. int passwordMatch (const char *password)
  178. {
  179. char *encrypted ;
  180. char salted [1024] ;
  181. sprintf (salted, "$6$%s$", salt) ;
  182. encrypted = crypt (password, salted) ;
  183. // 20: $6$ then 16 characters of salt, then $
  184. // 86 is the length of an SHA-512 hash
  185. return strncmp (encrypted + 20, returnedHash, 86) == 0 ;
  186. }
  187. /*
  188. * setupServer:
  189. * Do what's needed to create a local server socket instance that can listen
  190. * on both IPv4 and IPv6 interfaces.
  191. *********************************************************************************
  192. */
  193. int setupServer (int serverPort)
  194. {
  195. socklen_t clientSockAddrSize = sizeof (clientSockAddr) ;
  196. int on = 1 ;
  197. int family ;
  198. socklen_t serverSockAddrSize ;
  199. int clientFd ;
  200. // Try to create an IPv6 socket
  201. serverFd = socket (PF_INET6, SOCK_STREAM, 0) ;
  202. // If it didn't work, then fall-back to IPv4.
  203. if (serverFd < 0)
  204. {
  205. if ((serverFd = socket (PF_INET, SOCK_STREAM, 0)) < 0)
  206. return -1 ;
  207. family = AF_INET ;
  208. serverSockAddrSize = sizeof (struct sockaddr_in) ;
  209. }
  210. else // We got an IPv6 socket
  211. {
  212. family = AF_INET6 ;
  213. serverSockAddrSize = sizeof (struct sockaddr_in6) ;
  214. }
  215. if (setsockopt (serverFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
  216. return -1 ;
  217. // Setup the servers socket address - cope with IPv4 and v6.
  218. memset (&serverSockAddr, 0, sizeof (serverSockAddr)) ;
  219. switch (family)
  220. {
  221. case AF_INET:
  222. serverSockAddr.sin.sin_family = AF_INET ;
  223. serverSockAddr.sin.sin_addr.s_addr = htonl (INADDR_ANY) ;
  224. serverSockAddr.sin.sin_port = htons (serverPort) ;
  225. break;
  226. case AF_INET6:
  227. serverSockAddr.sin6.sin6_family = AF_INET6 ;
  228. serverSockAddr.sin6.sin6_addr = in6addr_any ;
  229. serverSockAddr.sin6.sin6_port = htons (serverPort) ;
  230. }
  231. // Bind, listen and accept
  232. if (bind (serverFd, (struct sockaddr *)&serverSockAddr, serverSockAddrSize) < 0)
  233. return -1 ;
  234. if (listen (serverFd, 4) < 0) // Really only going to talk to one client at a time...
  235. return -1 ;
  236. if ((clientFd = accept (serverFd, (struct sockaddr *)&clientSockAddr, &clientSockAddrSize)) < 0)
  237. return -1 ;
  238. return clientFd ;
  239. }
  240. /*
  241. * closeServer:
  242. *********************************************************************************
  243. */
  244. void closeServer (int clientFd)
  245. {
  246. if (serverFd != -1) close (serverFd) ;
  247. if (clientFd != -1) close (clientFd) ;
  248. serverFd = clientFd = -1 ;
  249. }