1 #include <sys/types.h>
2 #include <sys/socket.h>
3
4 #include <arpa/inet.h>
5 #include <netinet/in.h>
6
7 #include <err.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 static void
usage(const char * cmd)15 usage(const char *cmd)
16 {
17 fprintf(stderr, "%s -4 ip4 -p port [-t tos [-c]]\n", cmd);
18 exit(1);
19 }
20
21 int
main(int argc,char * argv[])22 main(int argc, char *argv[])
23 {
24 struct sockaddr_in in;
25 int s, opt, n, tos, cmsg_tos;
26 uint8_t buf[18];
27 struct msghdr msg;
28 struct iovec iov;
29 struct cmsghdr *cm;
30 union {
31 struct cmsghdr cm;
32 uint8_t data[CMSG_SPACE(sizeof(u_char))];
33 } ctrl;
34
35 memset(&in, 0, sizeof(in));
36 in.sin_family = AF_INET;
37 tos = -1;
38 cmsg_tos = 0;
39
40 while ((opt = getopt(argc, argv, "4:cp:t:")) != -1) {
41 switch (opt) {
42 case '4':
43 if (inet_pton(AF_INET, optarg, &in.sin_addr) <= 0)
44 usage(argv[0]);
45 break;
46
47 case 'c':
48 cmsg_tos = 1;
49 break;
50
51 case 'p':
52 in.sin_port = strtol(optarg, NULL, 10);
53 in.sin_port = htons(in.sin_port);
54 break;
55
56 case 't':
57 tos = strtol(optarg, NULL, 10);
58 break;
59
60 default:
61 usage(argv[0]);
62 }
63 }
64
65 if (in.sin_addr.s_addr == INADDR_ANY || in.sin_port == 0)
66 usage(argv[0]);
67
68 s = socket(AF_INET, SOCK_DGRAM, 0);
69 if (s < 0)
70 err(2, "socket failed");
71
72 if (tos >= 0) {
73 if (!cmsg_tos) {
74 if (setsockopt(s, IPPROTO_IP, IP_TOS,
75 &tos, sizeof(tos)) < 0)
76 err(2, "setsockopt IP_TOS %d failed", tos);
77
78 if (sendto(s, buf, sizeof(buf), 0,
79 (const struct sockaddr *)&in, sizeof(in)) < 0)
80 err(2, "sendto failed");
81 } else {
82 iov.iov_base = buf;
83 iov.iov_len = sizeof(buf);
84
85 memset(&msg, 0, sizeof(msg));
86 msg.msg_name = ∈
87 msg.msg_namelen = sizeof(in);
88 msg.msg_iov = &iov;
89 msg.msg_iovlen = 1;
90 msg.msg_control = ctrl.data;
91 msg.msg_controllen = sizeof(ctrl.data);
92
93 memset(&ctrl, 0, sizeof(ctrl));
94 cm = CMSG_FIRSTHDR(&msg);
95 cm->cmsg_len = CMSG_LEN(sizeof(u_char));
96 cm->cmsg_level = IPPROTO_IP;
97 cm->cmsg_type = IP_TOS;
98 *((u_char *)CMSG_DATA(cm)) = tos;
99
100 fprintf(stderr, "sendmsg tos %d\n", tos);
101 if (sendmsg(s, &msg, MSG_SYNC) < 0)
102 err(2, "sendmsg failed");
103 }
104 } else {
105 const int on = 1;
106
107 if (bind(s, (const struct sockaddr *)&in, sizeof(in)) < 0)
108 err(2, "bind failed");
109
110 if (setsockopt(s, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)) < 0)
111 err(2, "setsockopt IP_RECVTOS failed");
112
113 iov.iov_base = buf;
114 iov.iov_len = sizeof(buf);
115
116 memset(&msg, 0, sizeof(msg));
117 msg.msg_iov = &iov;
118 msg.msg_iovlen = 1;
119 msg.msg_control = ctrl.data;
120 msg.msg_controllen = sizeof(ctrl.data);
121
122 n = recvmsg(s, &msg, MSG_WAITALL);
123 if (n < 0)
124 err(1, "recvmsg failed");
125 else if (n != sizeof(buf))
126 errx(1, "recvmsg received %d", n);
127
128 cm = CMSG_FIRSTHDR(&msg);
129 if (cm == NULL)
130 errx(1, "no cmsg");
131 if (cm->cmsg_len != CMSG_LEN(sizeof(u_char)))
132 errx(1, "cmsg len mismatch");
133 if (cm->cmsg_level != IPPROTO_IP)
134 errx(1, "cmsg level mismatch");
135 if (cm->cmsg_type != IP_RECVTOS)
136 errx(1, "cmsg type mismatch");
137
138 tos = *((u_char *)CMSG_DATA(cm));
139
140 fprintf(stderr, "TOS: %d\n", tos);
141 }
142
143 exit(0);
144 }
145