dclib-network-linux.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /***************************************************************************
  2. * *
  3. * _____ ____ *
  4. * | __ \ / __ \ _ _ _____ *
  5. * | | \ \ / / \_\ | | | | _ \ *
  6. * | | \ \| | | | | | |_| | *
  7. * | | | || | | | | | ___/ *
  8. * | | / /| | __ | | | | _ \ *
  9. * | |__/ / \ \__/ / | |___| | |_| | *
  10. * |_____/ \____/ |_____|_|_____/ *
  11. * *
  12. * Wiimms source code library *
  13. * *
  14. ***************************************************************************
  15. * *
  16. * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
  17. * *
  18. ***************************************************************************
  19. * *
  20. * This library is free software; you can redistribute it and/or modify *
  21. * it under the terms of the GNU General Public License as published by *
  22. * the Free Software Foundation; either version 2 of the License, or *
  23. * (at your option) any later version. *
  24. * *
  25. * This library is distributed in the hope that it will be useful, *
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  28. * GNU General Public License for more details. *
  29. * *
  30. * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
  31. * *
  32. ***************************************************************************/
  33. #define _GNU_SOURCE 1
  34. #include <string.h>
  35. #include <netdb.h>
  36. #include <errno.h>
  37. #include <unistd.h>
  38. #include <ifaddrs.h>
  39. #include <sys/ioctl.h>
  40. #ifdef SYSTEM_LINUX
  41. #include <linux/route.h>
  42. #endif
  43. #include "dclib-network.h"
  44. //
  45. ///////////////////////////////////////////////////////////////////////////////
  46. /////////////// IP/UDP ///////////////
  47. ///////////////////////////////////////////////////////////////////////////////
  48. ssize_t ReceiveUDPv4
  49. (
  50. int sock, // valid socket
  51. void *buf, // buffer tostore incoming data
  52. size_t buf_size, // size of buffer
  53. int flags, // flags for recffrom() or recvmsg()
  54. struct sockaddr_in *src_addr, // not NULL: store source address
  55. in_addr_t *dest_addr // not NULL: store destination IPv4 (NBO)
  56. )
  57. {
  58. DASSERT(buf);
  59. if (!dest_addr)
  60. {
  61. socklen_t src_len = sizeof(*src_addr);
  62. return recvfrom( sock, buf, buf_size, flags,
  63. (struct sockaddr*)src_addr, &src_len );
  64. }
  65. struct sockaddr_in sa_temp;
  66. if (!src_addr)
  67. src_addr = &sa_temp;
  68. *dest_addr = 0;
  69. u8 control[CMSG_SPACE(sizeof(struct in_pktinfo))];
  70. struct iovec iov;
  71. iov.iov_base = buf;
  72. iov.iov_len = buf_size;
  73. struct msghdr msg = {0};
  74. msg.msg_name = src_addr;
  75. msg.msg_namelen = sizeof(*src_addr);
  76. msg.msg_iov = &iov;
  77. msg.msg_iovlen = 1;
  78. msg.msg_control = control;
  79. msg.msg_controllen = sizeof(control);
  80. ssize_t stat = recvmsg(sock,&msg,flags);
  81. if ( stat < 0 )
  82. return stat;
  83. struct cmsghdr *cp;
  84. for ( cp = CMSG_FIRSTHDR(&msg); cp; cp = CMSG_NXTHDR(&msg,cp))
  85. {
  86. if ( cp->cmsg_level == IPPROTO_IP && cp->cmsg_type == IP_PKTINFO )
  87. {
  88. struct in_pktinfo *pktinfo = (struct in_pktinfo*) CMSG_DATA(cp);
  89. *dest_addr = pktinfo->ipi_spec_dst.s_addr;
  90. break;
  91. }
  92. }
  93. return stat;
  94. }
  95. ///////////////////////////////////////////////////////////////////////////////
  96. ssize_t SendUDPv4
  97. (
  98. int sock, // valid socket
  99. const void *data, // data to send
  100. size_t data_size, // size of data
  101. int flags, // flags for sendto() or sendmsg()
  102. struct sockaddr_in *dest_addr, // destination address (NULL possible)
  103. in_addr_t src_addr // not 0: source IPv4 (NBO)
  104. )
  105. {
  106. DASSERT(data);
  107. DASSERT(dest_addr);
  108. if (!src_addr)
  109. return sendto(sock,data,data_size,flags,dest_addr,sizeof(*dest_addr));
  110. u8 control[CMSG_SPACE(sizeof(struct in_pktinfo))];
  111. struct iovec iov;
  112. iov.iov_base = (void*)data;
  113. iov.iov_len = data_size;
  114. struct msghdr msg = {0};
  115. msg.msg_name = dest_addr;
  116. msg.msg_namelen = sizeof(*dest_addr);
  117. msg.msg_iov = &iov;
  118. msg.msg_iovlen = 1;
  119. msg.msg_control = control;
  120. msg.msg_controllen = sizeof(control);
  121. struct cmsghdr *cp = CMSG_FIRSTHDR(&msg);
  122. cp->cmsg_level = IPPROTO_IP;
  123. cp->cmsg_type = IP_PKTINFO;
  124. cp->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
  125. struct in_pktinfo *pki = (struct in_pktinfo*) CMSG_DATA(cp);
  126. pki->ipi_ifindex = 0;
  127. pki->ipi_spec_dst.s_addr = src_addr;
  128. return sendmsg(sock,&msg,flags);
  129. }
  130. //
  131. ///////////////////////////////////////////////////////////////////////////////
  132. /////////////// SendRawUDP() ///////////////
  133. ///////////////////////////////////////////////////////////////////////////////
  134. enumError SendRawUDP
  135. (
  136. // Capability CAP_NET_RAW needed (or effective user ID of 0).
  137. int sock, // RAW socket to use,
  138. // if -1: open and close private socket
  139. ccp send_addr, // NULL or sender address:port
  140. u32 send_ip4, // fall back IP4, if 'send_addr' empty
  141. u16 send_port, // default sender port
  142. ccp recv_addr, // NULL or receiver address:port
  143. u32 recv_ip4, // fall back IP4, if 'recv_addr' empty
  144. u16 recv_port, // default receiver port
  145. const void *data, // data to send
  146. uint size, // size of 'data'
  147. uint log_mode // 0:silent, >0:print errors,
  148. // >=0x10: hexdump data, 'lmode' bytes max
  149. )
  150. {
  151. DASSERT( data || !size );
  152. //--- get addresses
  153. NetworkHost_t send_host;
  154. if ( send_addr && *send_addr )
  155. {
  156. if (!ResolveHost(&send_host,true,send_addr,send_port,false,false))
  157. {
  158. if (log_mode)
  159. ERROR1(ERR_ERROR,"Can't resolve sender host: %s\n",send_addr);
  160. return ERR_ERROR;
  161. }
  162. }
  163. else
  164. {
  165. send_host.sa.sin_family = AF_INET;
  166. send_host.sa.sin_addr.s_addr = htonl(send_ip4);
  167. send_host.sa.sin_port = htons(send_port);
  168. }
  169. NetworkHost_t recv_host;
  170. if ( recv_addr && *recv_addr )
  171. {
  172. if (!ResolveHost(&recv_host,true,recv_addr,recv_port,false,false))
  173. {
  174. if (log_mode)
  175. ERROR1(ERR_ERROR,"Can't resolve sender host: %s\n",recv_addr);
  176. return ERR_ERROR;
  177. }
  178. }
  179. else
  180. {
  181. recv_host.sa.sin_family = AF_INET;
  182. recv_host.sa.sin_addr.s_addr = htonl(recv_ip4);
  183. recv_host.sa.sin_port = htons(recv_port);
  184. }
  185. return SendRawUDPsa(sock,&send_host.sa,&recv_host.sa,data,size,log_mode);
  186. }
  187. ///////////////////////////////////////////////////////////////////////////////
  188. enumError SendRawUDPsa
  189. (
  190. // Capability CAP_NET_RAW needed (or effective user ID of 0).
  191. int sock, // RAW socket to use,
  192. // if -1: open and close private socket
  193. struct sockaddr_in *sa_send, // sockaddr of sender
  194. struct sockaddr_in *sa_recv, // sockaddr of receiver
  195. const void *data, // data to send
  196. uint size, // size of 'data'
  197. uint log_mode // 0:silent, >0:print errors,
  198. // >=0x10: hexdump data, 'lmode' bytes max
  199. )
  200. {
  201. DASSERT(sa_send);
  202. DASSERT(sa_recv);
  203. DASSERT( data || !size );
  204. if ( size > MAX_UDP_PACKET_DATA )
  205. size = MAX_UDP_PACKET_DATA;
  206. TRACE("Send %zu+%u bytes from %s to %s\n",
  207. sizeof(ip4_head_t) + sizeof(udp_head_t), size,
  208. PrintIP4sa(0,0,sa_send),
  209. PrintIP4sa(0,0,sa_recv) );
  210. //--- open socket
  211. enumError err = ERR_OK;
  212. const bool own_sock = sock == -1;
  213. if (own_sock)
  214. {
  215. sock = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
  216. if ( sock == -1 )
  217. {
  218. if (log_mode)
  219. ERROR1(ERR_CANT_CREATE,"Can't create RAW socket.\n");
  220. err = ERR_CANT_CREATE;
  221. goto abort;
  222. }
  223. int on = 1;
  224. setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
  225. }
  226. //--- setup packet
  227. udp_packet_t pkt;
  228. const uint total_len = SetupRawUDPsa(&pkt,sa_send,sa_recv,data,size);
  229. if ( log_mode >= 0x10 )
  230. HexDump16( stdwrn, 0, 0, &pkt,
  231. total_len < log_mode ? total_len : log_mode );
  232. //--- send data
  233. //HEXDUMP16(0,0,&pkt,total_len);
  234. //HexDump16(stderr,0,0,&pkt,total_len);
  235. int stat = sendto(sock,&pkt,total_len,0,(struct sockaddr*)sa_recv,sizeof(*sa_recv));
  236. if ( stat == -1 )
  237. {
  238. ERROR1(ERR_ERROR,"Can't send to sock %d\n",sock);
  239. if (log_mode)
  240. ERROR1(ERR_WRITE_FAILED,"Can't send to socket %d\n",sock);
  241. err = ERR_WRITE_FAILED;
  242. goto abort;
  243. }
  244. //--- close socket and terminate
  245. abort:
  246. if ( own_sock && sock != -1 )
  247. close(sock);
  248. return err;
  249. }
  250. ///////////////////////////////////////////////////////////////////////////////
  251. uint SetupRawUDPsa
  252. (
  253. // returns total packet len (mabe with limited 'size')
  254. udp_packet_t *pkt, // paket header to setup (cleared and written)
  255. struct sockaddr_in *sa_send, // sockaddr of sender
  256. struct sockaddr_in *sa_recv, // sockaddr of receiver
  257. const void *data, // data to send
  258. uint size // size of 'data'
  259. )
  260. {
  261. DASSERT(pkt);
  262. DASSERT(sa_send);
  263. DASSERT(sa_recv);
  264. DASSERT( data || !size );
  265. if ( size > MAX_UDP_PACKET_DATA )
  266. size = MAX_UDP_PACKET_DATA;
  267. //--- determine sender ip4
  268. u32 sender_ip4 = sa_send->sin_addr.s_addr;
  269. if (!sender_ip4)
  270. {
  271. RouteIP4_t rt;
  272. if (FindGatewayIP4(&rt,sa_recv->sin_addr.s_addr))
  273. sender_ip4 = GetIP4ByInterface(rt.iface);
  274. }
  275. //--- create data structure
  276. static const u8 ip4_head[]
  277. = { 0x45,0x00, 0x00,0x00, 0x12,0x34, 0x40,0x00, 0x40,0x11 };
  278. const uint total_len = sizeof(ip4_head_t) + sizeof(udp_head_t) + size;
  279. memset(pkt,0,sizeof(*pkt));
  280. memcpy(&pkt->ip4,ip4_head,sizeof(ip4_head));
  281. memcpy(pkt->data,data,size);
  282. pkt->ip4.ip_src = sender_ip4;
  283. pkt->ip4.ip_dest = sa_recv->sin_addr.s_addr;
  284. pkt->ip4.total_len = htons(total_len);
  285. pkt->ip4.checksum = CalcChecksumIP4(&pkt->ip4,sizeof(pkt->ip4));
  286. pkt->udp.port_src = sa_send->sin_port;
  287. pkt->udp.port_dest = sa_recv->sin_port;
  288. pkt->udp.data_len = htons(size+8);
  289. pkt->udp.checksum = CalcChecksumUDP(&pkt->ip4,&pkt->udp,data);
  290. //--- terminate
  291. //HEXDUMP16(0,0,&pkt,total_len);
  292. //HexDump16(stderr,0,0,&pkt,total_len);
  293. return total_len;
  294. }
  295. //
  296. ///////////////////////////////////////////////////////////////////////////////
  297. /////////////// Routing Support ///////////////
  298. ///////////////////////////////////////////////////////////////////////////////
  299. bool OpenRouteScanIP4
  300. (
  301. // returns TRUE on success and FALSE if no element is found
  302. RouteIP4_t *rt // valid data, will be initialized
  303. )
  304. {
  305. DASSERT(rt);
  306. memset(rt,0,sizeof(*rt));
  307. rt->index = -1;
  308. rt->col_iface = 0;
  309. rt->col_dest = 1;
  310. rt->col_mask = 7;
  311. rt->col_gate = 2;
  312. rt->col_flags = 3;
  313. #ifdef __CYGWIN__
  314. return false;
  315. #else
  316. rt->f = fopen("/proc/net/route","rb");
  317. if (!rt->f)
  318. return false;
  319. char *ptr = fgets(rt->buf,sizeof(rt->buf),rt->f);
  320. if (!ptr)
  321. return false;
  322. uint col;
  323. for ( col = 0; *ptr; col++ )
  324. {
  325. while ( *ptr == ' ' || *ptr == '\t' )
  326. ptr++;
  327. if (!*ptr)
  328. break;
  329. char *beg = ptr;
  330. while ( *ptr && *ptr != ' ' && *ptr != '\t' )
  331. ptr++;
  332. if (*ptr)
  333. *ptr++ = 0;
  334. if (!strcasecmp(beg,"Iface")) rt->col_iface = col;
  335. else if (!strcasecmp(beg,"Destination"))rt->col_dest = col;
  336. else if (!strcasecmp(beg,"Mask")) rt->col_mask = col;
  337. else if (!strcasecmp(beg,"Gateway")) rt->col_gate = col;
  338. else if (!strcasecmp(beg,"Flags")) rt->col_flags = col;
  339. }
  340. TRACE("f=%p, COLS: if=%d, dest=%d, mask=%d, gate=%d, flags=%d\n",
  341. rt->f, rt->col_iface, rt->col_dest,
  342. rt->col_mask, rt->col_gate, rt->col_flags );
  343. return NextRouteScanIP4(rt);
  344. #endif // !__CYGWIN__
  345. }
  346. ///////////////////////////////////////////////////////////////////////////////
  347. bool NextRouteScanIP4
  348. (
  349. // returns TRUE on success and FALSE if no more element is found
  350. RouteIP4_t *rt // valid data
  351. )
  352. {
  353. DASSERT(rt);
  354. #ifdef __CYGWIN__
  355. return false;
  356. #else
  357. char *ptr = fgets(rt->buf,sizeof(rt->buf),rt->f);
  358. if (!ptr)
  359. {
  360. rt->index = -1;
  361. return false;
  362. }
  363. uint col;
  364. for ( col = 0; *ptr; col++ )
  365. {
  366. while ( *ptr == ' ' || *ptr == '\t' )
  367. ptr++;
  368. if (!*ptr)
  369. break;
  370. char *beg = ptr;
  371. while ( *ptr && *ptr != ' ' && *ptr != '\t' )
  372. ptr++;
  373. if (*ptr)
  374. *ptr++ = 0;
  375. if ( col == rt->col_iface ) rt->iface = beg;
  376. else if ( col==rt->col_dest ) rt->dest = strtoul(beg,0,16);
  377. else if ( col==rt->col_mask ) rt->mask = strtoul(beg,0,16);
  378. else if ( col==rt->col_gate ) rt->gate = strtoul(beg,0,16);
  379. else if ( col==rt->col_flags ) rt->flags = strtoul(beg,0,16);
  380. }
  381. return true;
  382. #endif // !__CYGWIN__
  383. }
  384. ///////////////////////////////////////////////////////////////////////////////
  385. void CloseRouteScanIP4
  386. (
  387. RouteIP4_t *rt // valid data
  388. )
  389. {
  390. #ifndef __CYGWIN__
  391. DASSERT(rt);
  392. if (rt->f)
  393. {
  394. fclose(rt->f);
  395. rt->f = 0;
  396. }
  397. #endif // !__CYGWIN__
  398. }
  399. ///////////////////////////////////////////////////////////////////////////////
  400. ///////////////////////////////////////////////////////////////////////////////
  401. bool FindGatewayIP4
  402. (
  403. // returns TRUE if gateway found
  404. RouteIP4_t *rt, // valid data, will be initialized
  405. u32 ip4 // search gateway for this address (network byte order)
  406. )
  407. {
  408. DASSERT(rt);
  409. bool found;
  410. for ( found = OpenRouteScanIP4(rt); found; found = NextRouteScanIP4(rt) )
  411. {
  412. #ifdef __CYGWIN__
  413. if ( rt->dest == ( ip4 & rt->mask ))
  414. break;
  415. #else
  416. if ( !(rt->flags & RTF_UP) )
  417. continue;
  418. if ( rt->flags & RTF_HOST )
  419. {
  420. if ( rt->dest == ip4 )
  421. break;
  422. }
  423. else if ( rt->dest == ( ip4 & rt->mask ))
  424. break;
  425. #endif
  426. }
  427. CloseRouteScanIP4(rt);
  428. return found;
  429. }
  430. ///////////////////////////////////////////////////////////////////////////////
  431. ///////////////////////////////////////////////////////////////////////////////
  432. u32 GetIP4ByInterface
  433. ( // return 0 or IP4 in network byte order
  434. ccp iface // interface name. If NULL: Use default gateway
  435. )
  436. {
  437. RouteIP4_t rt;
  438. if ( !iface || !*iface )
  439. {
  440. if (!FindGatewayIP4(&rt,0))
  441. return 0;
  442. iface = rt.iface;
  443. }
  444. int sock = socket(AF_INET,SOCK_DGRAM,0);
  445. if ( sock == -1 )
  446. return 0;
  447. struct ifreq ifr;
  448. memset(&ifr,0,sizeof(ifr));
  449. ifr.ifr_addr.sa_family = AF_INET;
  450. strncpy(ifr.ifr_name,iface,sizeof(ifr.ifr_name)-1);
  451. int stat = ioctl(sock,SIOCGIFADDR,&ifr);
  452. close(sock);
  453. if ( stat == -1 )
  454. return 0;
  455. struct sockaddr_in *sa = (struct sockaddr_in*)&ifr.ifr_addr;
  456. return sa->sin_addr.s_addr;
  457. }
  458. //
  459. ///////////////////////////////////////////////////////////////////////////////
  460. /////////////// END ///////////////
  461. ///////////////////////////////////////////////////////////////////////////////