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 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 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