0001
0002
0003
0004 #define _GNU_SOURCE
0005
0006 #include <arpa/inet.h>
0007 #include <error.h>
0008 #include <errno.h>
0009 #include <limits.h>
0010 #include <linux/in6.h>
0011 #include <stdbool.h>
0012 #include <stdio.h>
0013 #include <stdint.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <sys/socket.h>
0017 #include <sys/stat.h>
0018 #include <sys/time.h>
0019 #include <sys/types.h>
0020 #include <sys/wait.h>
0021 #include <unistd.h>
0022
0023
0024 #ifndef IPV6_FLOWLABEL_MGR
0025 #define IPV6_FLOWLABEL_MGR 32
0026 #endif
0027
0028
0029 #define FL_MIN_LINGER 6
0030
0031 #define explain(x) \
0032 do { if (cfg_verbose) fprintf(stderr, " " x "\n"); } while (0)
0033
0034 #define __expect(x) \
0035 do { \
0036 if (!(x)) \
0037 fprintf(stderr, "[OK] " #x "\n"); \
0038 else \
0039 error(1, 0, "[ERR] " #x " (line %d)", __LINE__); \
0040 } while (0)
0041
0042 #define expect_pass(x) __expect(x)
0043 #define expect_fail(x) __expect(!(x))
0044
0045 static bool cfg_long_running;
0046 static bool cfg_verbose;
0047
0048 static int flowlabel_get(int fd, uint32_t label, uint8_t share, uint16_t flags)
0049 {
0050 struct in6_flowlabel_req req = {
0051 .flr_action = IPV6_FL_A_GET,
0052 .flr_label = htonl(label),
0053 .flr_flags = flags,
0054 .flr_share = share,
0055 };
0056
0057
0058 req.flr_dst.s6_addr[0] = 0xfd;
0059 req.flr_dst.s6_addr[15] = 0x1;
0060
0061 return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
0062 }
0063
0064 static int flowlabel_put(int fd, uint32_t label)
0065 {
0066 struct in6_flowlabel_req req = {
0067 .flr_action = IPV6_FL_A_PUT,
0068 .flr_label = htonl(label),
0069 };
0070
0071 return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
0072 }
0073
0074 static void run_tests(int fd)
0075 {
0076 int wstatus;
0077 pid_t pid;
0078
0079 explain("cannot get non-existent label");
0080 expect_fail(flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0));
0081
0082 explain("cannot put non-existent label");
0083 expect_fail(flowlabel_put(fd, 1));
0084
0085 explain("cannot create label greater than 20 bits");
0086 expect_fail(flowlabel_get(fd, 0x1FFFFF, IPV6_FL_S_ANY,
0087 IPV6_FL_F_CREATE));
0088
0089 explain("create a new label (FL_F_CREATE)");
0090 expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));
0091 explain("can get the label (without FL_F_CREATE)");
0092 expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0));
0093 explain("can get it again with create flag set, too");
0094 expect_pass(flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));
0095 explain("cannot get it again with the exclusive (FL_FL_EXCL) flag");
0096 expect_fail(flowlabel_get(fd, 1, IPV6_FL_S_ANY,
0097 IPV6_FL_F_CREATE | IPV6_FL_F_EXCL));
0098 explain("can now put exactly three references");
0099 expect_pass(flowlabel_put(fd, 1));
0100 expect_pass(flowlabel_put(fd, 1));
0101 expect_pass(flowlabel_put(fd, 1));
0102 expect_fail(flowlabel_put(fd, 1));
0103
0104 explain("create a new exclusive label (FL_S_EXCL)");
0105 expect_pass(flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));
0106 explain("cannot get it again in non-exclusive mode");
0107 expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));
0108 explain("cannot get it again in exclusive mode either");
0109 expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));
0110 expect_pass(flowlabel_put(fd, 2));
0111
0112 if (cfg_long_running) {
0113 explain("cannot reuse the label, due to linger");
0114 expect_fail(flowlabel_get(fd, 2, IPV6_FL_S_ANY,
0115 IPV6_FL_F_CREATE));
0116 explain("after sleep, can reuse");
0117 sleep(FL_MIN_LINGER * 2 + 1);
0118 expect_pass(flowlabel_get(fd, 2, IPV6_FL_S_ANY,
0119 IPV6_FL_F_CREATE));
0120 }
0121
0122 explain("create a new user-private label (FL_S_USER)");
0123 expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, IPV6_FL_F_CREATE));
0124 explain("cannot get it again in non-exclusive mode");
0125 expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_ANY, 0));
0126 explain("cannot get it again in exclusive mode");
0127 expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_EXCL, 0));
0128 explain("can get it again in user mode");
0129 expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));
0130 explain("child process can get it too, but not after setuid(nobody)");
0131 pid = fork();
0132 if (pid == -1)
0133 error(1, errno, "fork");
0134 if (!pid) {
0135 expect_pass(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));
0136 if (setuid(USHRT_MAX))
0137 fprintf(stderr, "[INFO] skip setuid child test\n");
0138 else
0139 expect_fail(flowlabel_get(fd, 3, IPV6_FL_S_USER, 0));
0140 exit(0);
0141 }
0142 if (wait(&wstatus) == -1)
0143 error(1, errno, "wait");
0144 if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
0145 error(1, errno, "wait: unexpected child result");
0146
0147 explain("create a new process-private label (FL_S_PROCESS)");
0148 expect_pass(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, IPV6_FL_F_CREATE));
0149 explain("can get it again");
0150 expect_pass(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0));
0151 explain("child process cannot can get it");
0152 pid = fork();
0153 if (pid == -1)
0154 error(1, errno, "fork");
0155 if (!pid) {
0156 expect_fail(flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0));
0157 exit(0);
0158 }
0159 if (wait(&wstatus) == -1)
0160 error(1, errno, "wait");
0161 if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
0162 error(1, errno, "wait: unexpected child result");
0163 }
0164
0165 static void parse_opts(int argc, char **argv)
0166 {
0167 int c;
0168
0169 while ((c = getopt(argc, argv, "lv")) != -1) {
0170 switch (c) {
0171 case 'l':
0172 cfg_long_running = true;
0173 break;
0174 case 'v':
0175 cfg_verbose = true;
0176 break;
0177 default:
0178 error(1, 0, "%s: parse error", argv[0]);
0179 }
0180 }
0181 }
0182
0183 int main(int argc, char **argv)
0184 {
0185 int fd;
0186
0187 parse_opts(argc, argv);
0188
0189 fd = socket(PF_INET6, SOCK_DGRAM, 0);
0190 if (fd == -1)
0191 error(1, errno, "socket");
0192
0193 run_tests(fd);
0194
0195 if (close(fd))
0196 error(1, errno, "close");
0197
0198 return 0;
0199 }