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 <stdint.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 static int 15 test_sendsrcaddr(int s, const struct sockaddr_in *remote, 16 const struct in_addr *src) 17 { 18 struct msghdr msg; 19 struct iovec iov; 20 union { 21 struct cmsghdr cm; 22 uint8_t data[CMSG_SPACE(sizeof(struct in_addr))]; 23 } ctrl; 24 struct cmsghdr *cm; 25 int n; 26 27 iov.iov_base = &n; 28 iov.iov_len = sizeof(n); 29 30 memset(&msg, 0, sizeof(msg)); 31 if (remote != NULL) { 32 msg.msg_name = __DECONST(void *, remote); 33 msg.msg_namelen = sizeof(*remote); 34 } 35 msg.msg_iov = &iov; 36 msg.msg_iovlen = 1; 37 msg.msg_control = ctrl.data; 38 msg.msg_controllen = sizeof(ctrl.data); 39 40 memset(&ctrl, 0, sizeof(ctrl)); 41 cm = CMSG_FIRSTHDR(&msg); 42 cm->cmsg_len = CMSG_LEN(sizeof(int)); 43 cm->cmsg_level = IPPROTO_IP; 44 cm->cmsg_type = IP_RECVDSTADDR; 45 *((struct in_addr *)CMSG_DATA(cm)) = *src; 46 47 return sendmsg(s, &msg, MSG_SYNC); 48 } 49 50 static void 51 usage(const char *cmd) 52 { 53 fprintf(stderr, "%s -4 ip4 -p port [-s src]\n", cmd); 54 exit(1); 55 } 56 57 int 58 main(int argc, char *argv[]) 59 { 60 struct sockaddr_in remote, local; 61 struct in_addr src; 62 socklen_t local_len; 63 char local_str[INET_ADDRSTRLEN]; 64 int s, opt, s2, on, n; 65 66 memset(&remote, 0, sizeof(remote)); 67 remote.sin_family = AF_INET; 68 69 src.s_addr = INADDR_ANY; 70 71 while ((opt = getopt(argc, argv, "4:p:s:")) != -1) { 72 switch (opt) { 73 case '4': 74 if (inet_pton(AF_INET, optarg, &remote.sin_addr) <= 0) 75 usage(argv[0]); 76 break; 77 78 case 'p': 79 remote.sin_port = strtol(optarg, NULL, 10); 80 remote.sin_port = htons(remote.sin_port); 81 break; 82 83 case 's': 84 if (inet_pton(AF_INET, optarg, &src) <= 0) 85 usage(argv[0]); 86 break; 87 88 default: 89 usage(argv[0]); 90 } 91 } 92 93 s = socket(AF_INET, SOCK_DGRAM, 0); 94 if (s < 0) 95 err(2, "socket faild"); 96 97 /* 98 * inp_laddr == ANY && src valid --> pass. 99 * inp_laddr == ANY && src invalid --> fail. 100 */ 101 if (test_sendsrcaddr(s, &remote, &src) < 0) 102 err(2, "sendsrcaddr failed"); 103 104 local_len = sizeof(local); 105 if (getsockname(s, (struct sockaddr *)&local, &local_len) < 0) 106 err(2, "getsockname failed"); 107 108 fprintf(stderr, "wildcard: laddr %s, lport %u\n", 109 inet_ntop(AF_INET, &local.sin_addr, local_str, sizeof(local_str)), 110 ntohs(local.sin_port)); 111 local.sin_addr = src; 112 113 s2 = socket(AF_INET, SOCK_DGRAM, 0); 114 if (s2 < 0) 115 err(2, "socket 2 failed"); 116 117 on = 1; 118 if (setsockopt(s2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 119 err(2, "setsockopt(REUSEADDR) failed"); 120 121 if (bind(s2, (const struct sockaddr *)&local, sizeof(local)) < 0) 122 err(2, "bind src failed"); 123 124 /* 125 * inp_laddr != ANY && src == inp_laddr --> pass. 126 */ 127 if (test_sendsrcaddr(s2, &remote, &src) < 0) 128 err(2, "sendsrcaddr 2 failed"); 129 130 /* 131 * Duplicated src/lport as s2 --> fail. 132 */ 133 if (test_sendsrcaddr(s, &remote, &src) > 0) 134 errx(2, "sendsrcaddr succeeded!?"); 135 136 close(s2); 137 138 if (connect(s, (const struct sockaddr *)&remote, sizeof(remote)) < 0) 139 err(2, "connect remote failed"); 140 141 local_len = sizeof(local); 142 if (getsockname(s, (struct sockaddr *)&local, &local_len) < 0) 143 err(2, "getsockname failed"); 144 fprintf(stderr, "connected: laddr %s, lport %u\n", 145 inet_ntop(AF_INET, &local.sin_addr, local_str, sizeof(local_str)), 146 ntohs(local.sin_port)); 147 148 /* 149 * Connected socket: 150 * if inp_laddr == src --> pass. 151 * if inp_laddr != src --> fail. 152 */ 153 n = test_sendsrcaddr(s, NULL, &src); 154 if (local.sin_addr.s_addr == src.s_addr) { 155 if (n < 0) 156 err(2, "sendsrcaddr 3 failed"); 157 } else { 158 if (n > 0) 159 errx(2, "sendsrcaddr 2 succeeded!?"); 160 } 161 162 s2 = socket(AF_INET, SOCK_DGRAM, 0); 163 if (s2 < 0) 164 err(2, "socket 3 failed"); 165 166 on = 1; 167 if (setsockopt(s2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 168 err(2, "setsockopt(REUSEADDR) failed"); 169 170 local.sin_addr.s_addr = INADDR_ANY; 171 if (bind(s2, (const struct sockaddr *)&local, sizeof(local)) < 0) 172 err(2, "bind * failed"); 173 174 /* 175 * Connected socket, implied laddr/lport bound: 176 * if inp_laddr == src --> pass. 177 * if inp_laddr != src --> fail. 178 * 179 * Wildcard bound above should not matter. 180 */ 181 local_len = sizeof(local); 182 if (getsockname(s, (struct sockaddr *)&local, &local_len) < 0) 183 err(2, "getsockname failed"); 184 n = test_sendsrcaddr(s, NULL, &src); 185 if (local.sin_addr.s_addr == src.s_addr) { 186 if (n < 0) 187 err(2, "sendsrcaddr 4 failed"); 188 } else { 189 if (n > 0) 190 errx(2, "sendsrcaddr 3 succeeded!?"); 191 } 192 193 close(s2); 194 195 exit(0); 196 } 197