ipv6_flowlabel_mgr.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Test IPV6_FLOWINFO_MGR */
  3. #define _GNU_SOURCE
  4. #include <arpa/inet.h>
  5. #include <error.h>
  6. #include <errno.h>
  7. #include <limits.h>
  8. #include <linux/in6.h>
  9. #include <stdbool.h>
  10. #include <stdio.h>
  11. #include <stdint.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/socket.h>
  15. #include <sys/stat.h>
  16. #include <sys/time.h>
  17. #include <sys/types.h>
  18. #include <sys/wait.h>
  19. #include <unistd.h>
  20. /* uapi/glibc weirdness may leave this undefined */
  21. #ifndef IPV6_FLOWLABEL_MGR
  22. #define IPV6_FLOWLABEL_MGR 32
  23. #endif
  24. /* from net/ipv6/ip6_flowlabel.c */
  25. #define FL_MIN_LINGER 6
  26. #define explain(x) \
  27. do { if (cfg_verbose) fprintf(stderr, " " x "\n"); } while (0)
  28. #define __expect(x) \
  29. do { \
  30. if (!(x)) \
  31. fprintf(stderr, "[OK] " #x "\n"); \
  32. else \
  33. error(1, 0, "[ERR] " #x " (line %d)", __LINE__); \
  34. } while (0)
  35. #define expect_pass(x) __expect(x)
  36. #define expect_fail(x) __expect(!(x))
  37. static bool cfg_long_running;
  38. static bool cfg_verbose;
  39. static int flowlabel_get(int fd, uint32_t label, uint8_t share, uint16_t flags)
  40. {
  41. struct in6_flowlabel_req req = {
  42. .flr_action = IPV6_FL_A_GET,
  43. .flr_label = htonl(label),
  44. .flr_flags = flags,
  45. .flr_share = share,
  46. };
  47. /* do not pass IPV6_ADDR_ANY or IPV6_ADDR_MAPPED */
  48. req.flr_dst.s6_addr[0] = 0xfd;
  49. req.flr_dst.s6_addr[15] = 0x1;
  50. return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
  51. }
  52. static int flowlabel_put(int fd, uint32_t label)
  53. {
  54. struct in6_flowlabel_req req = {
  55. .flr_action = IPV6_FL_A_PUT,
  56. .flr_label = htonl(label),
  57. };
  58. return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
  59. }
  60. static void run_tests(int fd)
  61. {
  62. int wstatus;
  63. pid_t pid;
  64. explain("cannot get non-existent label");
  65. expect_fail(flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0));
  66. explain("cannot put non-existent label");
  67. expect_fail(flowlabel_put(fd, 1));
  68. explain("cannot create label greater than 20 bits");
  69. expect_fail(flowlabel_get(fd, 0x1FFFFF, IPV6_FL_S_ANY,
  70. IPV6_FL_F_CREATE));
  71. explain("create a new label (FL_F_CREATE)");
  72. expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));
  73. explain("can get the label (without FL_F_CREATE)");
  74. expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0));
  75. explain("can get it again with create flag set, too");
  76. expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));
  77. explain("cannot get it again with the exclusive (FL_FL_EXCL) flag");
  78. expect_fail(flowlabel_get(fd, 1, IPV6_FL_S_ANY,
  79. IPV6_FL_F_CREATE | IPV6_FL_F_EXCL));
  80. explain("can now put exactly three references");
  81. expect_pass(flowlabel_put(fd, 1));
  82. expect_pass(flowlabel_put(fd, 1));
  83. expect_pass(flowlabel_put(fd, 1));
  84. expect_fail(flowlabel_put(fd, 1));
  85. explain("create a new exclusive label (FL_S_EXCL)");
  86. expect_pass(flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));
  87. explain("cannot get it again in non-exclusive mode");
  88. expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));
  89. explain("cannot get it again in exclusive mode either");
  90. expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));
  91. expect_pass(flowlabel_put(fd, 2));
  92. if (cfg_long_running) {
  93. explain("cannot reuse the label, due to linger");
  94. expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_ANY,
  95. IPV6_FL_F_CREATE));
  96. explain("after sleep, can reuse");
  97. sleep(FL_MIN_LINGER * 2 + 1);
  98. expect_pass(flowlabel_get(fd, 2, IPV6_FL_S_ANY,
  99. IPV6_FL_F_CREATE));
  100. }
  101. explain("create a new user-private label (FL_S_USER)");
  102. expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, IPV6_FL_F_CREATE));
  103. explain("cannot get it again in non-exclusive mode");
  104. expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_ANY, 0));
  105. explain("cannot get it again in exclusive mode");
  106. expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_EXCL, 0));
  107. explain("can get it again in user mode");
  108. expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));
  109. explain("child process can get it too, but not after setuid(nobody)");
  110. pid = fork();
  111. if (pid == -1)
  112. error(1, errno, "fork");
  113. if (!pid) {
  114. expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));
  115. if (setuid(USHRT_MAX))
  116. fprintf(stderr, "[INFO] skip setuid child test\n");
  117. else
  118. expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));
  119. exit(0);
  120. }
  121. if (wait(&wstatus) == -1)
  122. error(1, errno, "wait");
  123. if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
  124. error(1, errno, "wait: unexpected child result");
  125. explain("create a new process-private label (FL_S_PROCESS)");
  126. expect_pass(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, IPV6_FL_F_CREATE));
  127. explain("can get it again");
  128. expect_pass(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0));
  129. explain("child process cannot can get it");
  130. pid = fork();
  131. if (pid == -1)
  132. error(1, errno, "fork");
  133. if (!pid) {
  134. expect_fail(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0));
  135. exit(0);
  136. }
  137. if (wait(&wstatus) == -1)
  138. error(1, errno, "wait");
  139. if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
  140. error(1, errno, "wait: unexpected child result");
  141. }
  142. static void parse_opts(int argc, char **argv)
  143. {
  144. int c;
  145. while ((c = getopt(argc, argv, "lv")) != -1) {
  146. switch (c) {
  147. case 'l':
  148. cfg_long_running = true;
  149. break;
  150. case 'v':
  151. cfg_verbose = true;
  152. break;
  153. default:
  154. error(1, 0, "%s: parse error", argv[0]);
  155. }
  156. }
  157. }
  158. int main(int argc, char **argv)
  159. {
  160. int fd;
  161. parse_opts(argc, argv);
  162. fd = socket(PF_INET6, SOCK_DGRAM, 0);
  163. if (fd == -1)
  164. error(1, errno, "socket");
  165. run_tests(fd);
  166. if (close(fd))
  167. error(1, errno, "close");
  168. return 0;
  169. }