NetPlatform_linux.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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. * For the second operand, we're grateful to android/bionic, platform level 21.
  34. */
  35. #if !defined(_LINUX_IN6_H) && !defined(_UAPI_LINUX_IN6_H)
  36. struct in6_ifreq
  37. {
  38. struct in6_addr ifr6_addr;
  39. uint32_t ifr6_prefixlen;
  40. int ifr6_ifindex;
  41. };
  42. #endif
  43. /**
  44. * Get a socket and ifRequest for a given interface by name.
  45. *
  46. * @param interfaceName the name of the interface, eg: tun0
  47. * @param af either AF_INET or AF_INET6
  48. * @param eg an exception handler in case something goes wrong.
  49. * this will send a -1 for all errors.
  50. * @param ifRequestOut an ifreq which will be populated with the interface index of the interface.
  51. * @return a socket for interacting with this interface.
  52. */
  53. static int socketForIfName(const char* interfaceName,
  54. int af,
  55. struct Except* eh,
  56. struct ifreq* ifRequestOut)
  57. {
  58. int s;
  59. if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
  60. Except_throw(eh, "socket() [%s]", strerror(errno));
  61. }
  62. memset(ifRequestOut, 0, sizeof(struct ifreq));
  63. strncpy(ifRequestOut->ifr_name, interfaceName, IFNAMSIZ);
  64. if (ioctl(s, SIOCGIFINDEX, ifRequestOut) < 0) {
  65. int err = errno;
  66. close(s);
  67. Except_throw(eh, "ioctl(SIOCGIFINDEX) [%s]", strerror(err));
  68. }
  69. return s;
  70. }
  71. static void checkInterfaceUp(int socket,
  72. struct ifreq* ifRequest,
  73. struct Log* logger,
  74. struct Except* eh)
  75. {
  76. if (ioctl(socket, SIOCGIFFLAGS, ifRequest) < 0) {
  77. int err = errno;
  78. close(socket);
  79. Except_throw(eh, "ioctl(SIOCGIFFLAGS) [%s]", strerror(err));
  80. }
  81. if (ifRequest->ifr_flags & IFF_UP & IFF_RUNNING) {
  82. // already up.
  83. return;
  84. }
  85. Log_info(logger, "Bringing up interface [%s]", ifRequest->ifr_name);
  86. ifRequest->ifr_flags |= IFF_UP | IFF_RUNNING;
  87. if (ioctl(socket, SIOCSIFFLAGS, ifRequest) < 0) {
  88. int err = errno;
  89. close(socket);
  90. Except_throw(eh, "ioctl(SIOCSIFFLAGS) [%s]", strerror(err));
  91. }
  92. }
  93. void NetPlatform_addAddress(const char* interfaceName,
  94. const uint8_t* address,
  95. int prefixLen,
  96. int addrFam,
  97. struct Log* logger,
  98. struct Except* eh)
  99. {
  100. struct ifreq ifRequest;
  101. int s = socketForIfName(interfaceName, addrFam, eh, &ifRequest);
  102. int ifIndex = ifRequest.ifr_ifindex;
  103. // checkInterfaceUp() clobbers the ifindex.
  104. checkInterfaceUp(s, &ifRequest, logger, eh);
  105. if (addrFam == Sockaddr_AF_INET6) {
  106. struct in6_ifreq ifr6 = {
  107. .ifr6_ifindex = ifIndex,
  108. .ifr6_prefixlen = prefixLen
  109. };
  110. memcpy(&ifr6.ifr6_addr, address, 16);
  111. if (ioctl(s, SIOCSIFADDR, &ifr6) < 0) {
  112. int err = errno;
  113. close(s);
  114. Except_throw(eh, "ioctl(SIOCSIFADDR) [%s]", strerror(err));
  115. }
  116. } else if (addrFam == Sockaddr_AF_INET) {
  117. struct sockaddr_in sin = { .sin_family = AF_INET, .sin_port = 0 };
  118. memcpy(&sin.sin_addr.s_addr, address, 4);
  119. memcpy(&ifRequest.ifr_addr, &sin, sizeof(struct sockaddr));
  120. if (ioctl(s, SIOCSIFADDR, &ifRequest) < 0) {
  121. int err = errno;
  122. close(s);
  123. Except_throw(eh, "ioctl(SIOCSIFADDR) failed: [%s]", strerror(err));
  124. }
  125. uint32_t x = ~0 << (32 - prefixLen);
  126. x = Endian_hostToBigEndian32(x);
  127. memcpy(&sin.sin_addr, &x, 4);
  128. memcpy(&ifRequest.ifr_addr, &sin, sizeof(struct sockaddr_in));
  129. if (ioctl(s, SIOCSIFNETMASK, &ifRequest) < 0) {
  130. int err = errno;
  131. close(s);
  132. Except_throw(eh, "ioctl(SIOCSIFNETMASK) failed: [%s]", strerror(err));
  133. }
  134. } else {
  135. Assert_true(0);
  136. }
  137. close(s);
  138. }
  139. void NetPlatform_setMTU(const char* interfaceName,
  140. uint32_t mtu,
  141. struct Log* logger,
  142. struct Except* eh)
  143. {
  144. struct ifreq ifRequest;
  145. int s = socketForIfName(interfaceName, AF_INET6, eh, &ifRequest);
  146. Log_info(logger, "Setting MTU for device [%s] to [%u] bytes.", interfaceName, mtu);
  147. ifRequest.ifr_mtu = mtu;
  148. if (ioctl(s, SIOCSIFMTU, &ifRequest) < 0) {
  149. int err = errno;
  150. close(s);
  151. Except_throw(eh, "ioctl(SIOCSIFMTU) [%s]", strerror(err));
  152. }
  153. close(s);
  154. }