NetPlatform_linux.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "util/platform/netdev/NetPlatform.h"
  16. #include "util/platform/Sockaddr.h"
  17. #include <string.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <sys/ioctl.h>
  21. #include <fcntl.h>
  22. #include <unistd.h>
  23. #include <sys/socket.h>
  24. #include <sys/types.h>
  25. #include <stdlib.h>
  26. #include <stddef.h>
  27. #include <net/if.h>
  28. #include <arpa/inet.h>
  29. #include <linux/if.h>
  30. /**
  31. * This hack exists because linux/in.h and linux/in6.h define
  32. * the same structures, leading to redefinition errors.
  33. */
  34. #ifndef _LINUX_IN6_H
  35. struct in6_ifreq
  36. {
  37. struct in6_addr ifr6_addr;
  38. uint32_t ifr6_prefixlen;
  39. int ifr6_ifindex;
  40. };
  41. #endif
  42. /**
  43. * Get a socket and ifRequest for a given interface by name.
  44. *
  45. * @param interfaceName the name of the interface, eg: tun0
  46. * @param af either AF_INET or AF_INET6
  47. * @param eg an exception handler in case something goes wrong.
  48. * this will send a -1 for all errors.
  49. * @param ifRequestOut an ifreq which will be populated with the interface index of the interface.
  50. * @return a socket for interacting with this interface.
  51. */
  52. static int socketForIfName(const char* interfaceName,
  53. int af,
  54. struct Except* eh,
  55. struct ifreq* ifRequestOut)
  56. {
  57. int s;
  58. if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
  59. Except_throw(eh, "socket() [%s]", strerror(errno));
  60. }
  61. memset(ifRequestOut, 0, sizeof(struct ifreq));
  62. strncpy(ifRequestOut->ifr_name, interfaceName, IFNAMSIZ);
  63. if (ioctl(s, SIOCGIFINDEX, ifRequestOut) < 0) {
  64. int err = errno;
  65. close(s);
  66. Except_throw(eh, "ioctl(SIOCGIFINDEX) [%s]", strerror(err));
  67. }
  68. return s;
  69. }
  70. static void checkInterfaceUp(int socket,
  71. struct ifreq* ifRequest,
  72. struct Log* logger,
  73. struct Except* eh)
  74. {
  75. if (ioctl(socket, SIOCGIFFLAGS, ifRequest) < 0) {
  76. int err = errno;
  77. close(socket);
  78. Except_throw(eh, "ioctl(SIOCGIFFLAGS) [%s]", strerror(err));
  79. }
  80. if (ifRequest->ifr_flags & IFF_UP & IFF_RUNNING) {
  81. // already up.
  82. return;
  83. }
  84. Log_info(logger, "Bringing up interface [%s]", ifRequest->ifr_name);
  85. ifRequest->ifr_flags |= IFF_UP | IFF_RUNNING;
  86. if (ioctl(socket, SIOCSIFFLAGS, ifRequest) < 0) {
  87. int err = errno;
  88. close(socket);
  89. Except_throw(eh, "ioctl(SIOCSIFFLAGS) [%s]", strerror(err));
  90. }
  91. }
  92. void NetPlatform_addAddress(const char* interfaceName,
  93. const uint8_t* address,
  94. int prefixLen,
  95. int addrFam,
  96. struct Log* logger,
  97. struct Except* eh)
  98. {
  99. struct ifreq ifRequest;
  100. int s = socketForIfName(interfaceName, addrFam, eh, &ifRequest);
  101. int ifIndex = ifRequest.ifr_ifindex;
  102. // checkInterfaceUp() clobbers the ifindex.
  103. checkInterfaceUp(s, &ifRequest, logger, eh);
  104. if (addrFam == Sockaddr_AF_INET6) {
  105. struct in6_ifreq ifr6 = {
  106. .ifr6_ifindex = ifIndex,
  107. .ifr6_prefixlen = prefixLen
  108. };
  109. memcpy(&ifr6.ifr6_addr, address, 16);
  110. if (ioctl(s, SIOCSIFADDR, &ifr6) < 0) {
  111. int err = errno;
  112. close(s);
  113. Except_throw(eh, "ioctl(SIOCSIFADDR) [%s]", strerror(err));
  114. }
  115. } else if (addrFam == Sockaddr_AF_INET) {
  116. struct sockaddr_in sin = { .sin_family = AF_INET, .sin_port = 0 };
  117. memcpy(&sin.sin_addr.s_addr, address, 4);
  118. memcpy(&ifRequest.ifr_addr, &sin, sizeof(struct sockaddr));
  119. if (ioctl(s, SIOCSIFADDR, &ifRequest) < 0) {
  120. int err = errno;
  121. close(s);
  122. Except_throw(eh, "ioctl(SIOCSIFADDR) failed: [%s]", strerror(err));
  123. }
  124. uint32_t x = ~0 << (32 - prefixLen);
  125. x = Endian_hostToBigEndian32(x);
  126. memcpy(&sin.sin_addr, &x, 4);
  127. memcpy(&ifRequest.ifr_addr, &sin, sizeof(struct sockaddr_in));
  128. if (ioctl(s, SIOCSIFNETMASK, &ifRequest) < 0) {
  129. int err = errno;
  130. close(s);
  131. Except_throw(eh, "ioctl(SIOCSIFNETMASK) failed: [%s]", strerror(err));
  132. }
  133. } else {
  134. Assert_true(0);
  135. }
  136. close(s);
  137. }
  138. void NetPlatform_setMTU(const char* interfaceName,
  139. uint32_t mtu,
  140. struct Log* logger,
  141. struct Except* eh)
  142. {
  143. struct ifreq ifRequest;
  144. int s = socketForIfName(interfaceName, AF_INET6, eh, &ifRequest);
  145. Log_info(logger, "Setting MTU for device [%s] to [%u] bytes.", interfaceName, mtu);
  146. ifRequest.ifr_mtu = mtu;
  147. if (ioctl(s, SIOCSIFMTU, &ifRequest) < 0) {
  148. int err = errno;
  149. close(s);
  150. Except_throw(eh, "ioctl(SIOCSIFMTU) [%s]", strerror(err));
  151. }
  152. close(s);
  153. }