ctdb-tests: Fix signed/unsigned comparisons by casting
[samba.git] / ctdb / tests / src / system_socket_test.c
1 /*
2    Raw socket (un) marshalling tests
3
4    Copyright (C) Martin Schwenke  2018
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21
22 #include <assert.h>
23
24 /* For ether_aton() */
25 #ifdef _AIX
26 #include <arpa/inet.h>
27 #endif
28 #ifdef __FreeBSD__
29 #include <net/ethernet.h>
30 #endif
31 #ifdef linux
32 #include <netinet/ether.h>
33 #endif
34
35 #include "common/system_socket.c"
36
37 #include "protocol/protocol_util.h"
38
39 static void test_types(void)
40 {
41         /*
42          * We use this struct in the code but don't pack it due to
43          * portability concerns.  It should have no padding.
44          */
45         struct {
46                 struct ip ip;
47                 struct tcphdr tcp;
48         } ip4pkt;
49
50         assert(sizeof(ip4pkt) == sizeof(struct ip) + sizeof(struct tcphdr));
51 }
52
53 #ifdef HAVE_PACKETSOCKET
54
55 static void test_arp(const char *addr_str, const char *hwaddr_str, bool reply)
56 {
57         ctdb_sock_addr addr;
58         struct ether_addr *hw, *dhw;
59         uint8_t buf[512];
60         size_t buflen = sizeof(buf);
61         size_t len;
62         ssize_t num_written;
63         int ret;
64
65         ret = ctdb_sock_addr_from_string(addr_str, &addr, false);
66         assert(ret == 0);
67
68         hw = ether_aton(hwaddr_str);
69         assert(hw != NULL);
70
71         switch (addr.ip.sin_family) {
72         case AF_INET:
73                 ret = arp_build(buf, buflen, &addr.ip, hw, reply, &dhw, &len);
74                 break;
75         case AF_INET6:
76                 ret = ip6_na_build(buf, buflen, &addr.ip6, hw, &dhw, &len);
77                 break;
78         default:
79                 abort();
80         }
81
82         assert(ret == 0);
83
84         num_written = write(STDOUT_FILENO, buf, len);
85         assert(num_written != -1 && (size_t)num_written == len);
86 }
87
88 #else /* HAVE_PACKETSOCKET  */
89
90 static void test_arp(const char *addr_str, const char *hwaddr_str, bool reply)
91 {
92         fprintf(stderr, "PACKETSOCKET not supported\n");
93 }
94
95 #endif /* HAVE_PACKETSOCKET */
96
97 static void test_tcp(const char *src_str,
98                      const char *dst_str,
99                      const char *seq_str,
100                      const char *ack_str,
101                      const char *rst_str)
102 {
103         ctdb_sock_addr src, dst;
104         uint32_t seq, ack;
105         int rst;
106         uint8_t buf[512];
107         struct ether_header *eth;
108         size_t expected_len, len;
109         ssize_t num_written;
110         char src_str_out[64], dst_str_out[64];
111         uint32_t seq_out, ack_out;
112         int rst_out = 0;
113         uint16_t window;
114         int ret;
115
116         ret = ctdb_sock_addr_from_string(src_str, &src, true);
117         assert(ret == 0);
118
119         ret = ctdb_sock_addr_from_string(dst_str, &dst, true);
120         assert(ret == 0);
121
122         seq = atoi(seq_str);
123         ack = atoi(ack_str);
124         rst = atoi(rst_str);
125
126         /* Need to fake this up */
127         eth = (struct ether_header *) buf;
128         memset(eth, 0, sizeof(*eth));
129
130         switch (src.ip.sin_family) {
131         case AF_INET:
132                 eth->ether_type = htons(ETHERTYPE_IP);
133                 expected_len = 40;
134                 ret = tcp4_build(buf + sizeof(struct ether_header),
135                                  sizeof(buf) - sizeof(struct ether_header),
136                                  &src.ip,
137                                  &dst.ip,
138                                  seq,
139                                  ack,
140                                  rst,
141                                  &len);
142                 break;
143         case AF_INET6:
144                 eth->ether_type = htons(ETHERTYPE_IP6);
145                 expected_len = 60;
146                 ret = tcp6_build(buf + sizeof(struct ether_header),
147                                  sizeof(buf) - sizeof(struct ether_header),
148                                  &src.ip6,
149                                  &dst.ip6,
150                                  seq,
151                                  ack,
152                                  rst,
153                                  &len);
154                 break;
155         default:
156                 abort();
157         }
158
159         assert(ret == 0);
160         assert(len == expected_len);
161
162         num_written = write(STDOUT_FILENO,
163                             buf + sizeof(struct ether_header),
164                             len);
165         assert(num_written != -1 && (size_t)num_written == len);
166
167         switch (ntohs(eth->ether_type)) {
168         case ETHERTYPE_IP:
169                 ret = tcp4_extract(buf + sizeof(struct ether_header),
170                                    len,
171                                    &src.ip,
172                                    &dst.ip,
173                                    &ack_out,
174                                    &seq_out,
175                                    &rst_out,
176                                    &window);
177                 break;
178         case ETHERTYPE_IP6:
179                 ret = tcp6_extract(buf + sizeof(struct ether_header),
180                                    len,
181                                    &src.ip6,
182                                    &dst.ip6,
183                                    &ack_out,
184                                    &seq_out,
185                                    &rst_out,
186                                    &window);
187                 break;
188         default:
189                 abort();
190         }
191
192         assert(ret == 0);
193
194         assert(seq == seq_out);
195         assert(ack == ack_out);
196         assert((rst != 0) == (rst_out != 0));
197         assert(window == htons(1234));
198
199         ret = ctdb_sock_addr_to_buf(src_str_out, sizeof(src_str_out),
200                                     &src, true);
201         assert(ret == 0);
202         ret = strcmp(src_str, src_str_out);
203         assert(ret == 0);
204
205         ret = ctdb_sock_addr_to_buf(dst_str_out, sizeof(dst_str_out),
206                                     &dst, true);
207         assert(ret == 0);
208         ret = strcmp(dst_str, dst_str_out);
209         assert(ret == 0);
210 }
211
212 static void usage(const char *prog)
213 {
214         fprintf(stderr, "usage: %s <cmd> [<arg> ...]\n", prog);
215         fprintf(stderr, "  commands:\n");
216         fprintf(stderr, "    types\n");
217         fprintf(stderr, "    arp <ipaddr> <hwaddr> [reply]\n");
218         fprintf(stderr, "    tcp <src> <dst> <seq> <ack> <rst>\n");
219
220         exit(1);
221 }
222
223 int main(int argc, char **argv)
224 {
225
226         if (argc < 2) {
227                 usage(argv[0]);
228         }
229
230         if (strcmp(argv[1], "types") == 0) {
231                 test_types();
232         } else if (strcmp(argv[1], "arp") == 0) {
233                 /*
234                  * Extra arg indicates that a reply should be
235                  * constructed for IPv4 - value is ignored
236                  */
237                 if (argc != 4 && argc != 5) {
238                         usage(argv[0]);
239                 }
240                 test_arp(argv[2], argv[3], (argc == 5));
241         } else if (strcmp(argv[1], "tcp") == 0) {
242                 if (argc != 7) {
243                         usage(argv[0]);
244                 }
245                 test_tcp(argv[2], argv[3], argv[4], argv[5], argv[6]);
246         } else {
247                 usage(argv[0]);
248         }
249
250         return 0;
251 }