ctdb-common: Add command line processing abstraction
[vlendec/samba-autobuild/.git] / ctdb / common / system_freebsd.c
1 /* 
2    ctdb system specific code to manage raw sockets on freebsd
3
4    Copyright (C) Ronnie Sahlberg  2007
5    Copyright (C) Andrew Tridgell  2007
6    Copyright (C) Marc Dequènes (Duck) 2009
7    Copyright (C) Volker Lendecke 2012
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, see <http://www.gnu.org/licenses/>.
21
22
23   This file is a copy of 'common/system_linux.c' adapted for Hurd^W kFreeBSD
24   needs, and inspired by 'common/system_aix.c' for the pcap usage.
25 */
26
27 #include "replace.h"
28 #include "system/network.h"
29 #include "system/filesys.h"
30 #include "system/wait.h"
31
32 #include "lib/util/debug.h"
33 #include "lib/util/blocking.h"
34
35 #include "protocol/protocol.h"
36
37 #include <net/ethernet.h>
38 #include <netinet/ip6.h>
39 #include <net/if_arp.h>
40 #include <pcap.h>
41
42 #include "common/logging.h"
43 #include "common/system.h"
44
45 #ifndef ETHERTYPE_IP6
46 #define ETHERTYPE_IP6 0x86dd
47 #endif
48
49 /*
50   calculate the tcp checksum for tcp over ipv6
51 */
52 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
53 {
54         uint32_t phdr[2];
55         uint32_t sum = 0;
56         uint16_t sum2;
57
58         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
59         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
60
61         phdr[0] = htonl(n);
62         phdr[1] = htonl(ip6->ip6_nxt);
63         sum += uint16_checksum((uint16_t *)phdr, 8);
64
65         sum += uint16_checksum(data, n);
66
67         sum = (sum & 0xFFFF) + (sum >> 16);
68         sum = (sum & 0xFFFF) + (sum >> 16);
69         sum2 = htons(sum);
70         sum2 = ~sum2;
71         if (sum2 == 0) {
72                 return 0xFFFF;
73         }
74         return sum2;
75 }
76
77 /*
78   send gratuitous arp reply after we have taken over an ip address
79
80   saddr is the address we are trying to claim
81   iface is the interface name we will be using to claim the address
82  */
83 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
84 {
85         /* FIXME FreeBSD: We don't do gratuitous arp yet */
86         return -1;
87 }
88
89
90 /*
91   simple TCP checksum - assumes data is multiple of 2 bytes long
92  */
93 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
94 {
95         uint32_t sum = uint16_checksum(data, n);
96         uint16_t sum2;
97         sum += uint16_checksum((uint16_t *)(void *)&ip->ip_src,
98                                sizeof(ip->ip_src));
99         sum += uint16_checksum((uint16_t *)(void *)&ip->ip_dst,
100                                sizeof(ip->ip_dst));
101         sum += ip->ip_p + n;
102         sum = (sum & 0xFFFF) + (sum >> 16);
103         sum = (sum & 0xFFFF) + (sum >> 16);
104         sum2 = htons(sum);
105         sum2 = ~sum2;
106         if (sum2 == 0) {
107                 return 0xFFFF;
108         }
109         return sum2;
110 }
111
112 /*
113   Send tcp segment from the specified IP/port to the specified
114   destination IP/port. 
115
116   This is used to trigger the receiving host into sending its own ACK,
117   which should trigger early detection of TCP reset by the client
118   after IP takeover
119
120   This can also be used to send RST segments (if rst is true) and also
121   if correct seq and ack numbers are provided.
122  */
123 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, 
124                       const ctdb_sock_addr *src,
125                       uint32_t seq, uint32_t ack, int rst)
126 {
127         int s;
128         int ret;
129         uint32_t one = 1;
130         uint16_t tmpport;
131         ctdb_sock_addr *tmpdest;
132         struct {
133                 struct ip ip;
134                 struct tcphdr tcp;
135         } ip4pkt;
136         struct {
137                 struct ip6_hdr ip6;
138                 struct tcphdr tcp;
139         } ip6pkt;
140         int saved_errno;
141
142         switch (src->ip.sin_family) {
143         case AF_INET:
144                 ZERO_STRUCT(ip4pkt);
145                 ip4pkt.ip.ip_v  = 4;
146                 ip4pkt.ip.ip_hl    = sizeof(ip4pkt.ip)/4;
147                 ip4pkt.ip.ip_len   = htons(sizeof(ip4pkt));
148                 ip4pkt.ip.ip_ttl   = 255;
149                 ip4pkt.ip.ip_p     = IPPROTO_TCP;
150                 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
151                 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
152                 ip4pkt.ip.ip_sum   = 0;
153
154                 ip4pkt.tcp.th_sport = src->ip.sin_port;
155                 ip4pkt.tcp.th_dport = dest->ip.sin_port;
156                 ip4pkt.tcp.th_seq   = seq;
157                 ip4pkt.tcp.th_ack   = ack;
158                 ip4pkt.tcp.th_flags = 0;
159                 ip4pkt.tcp.th_flags |= TH_ACK;
160                 if (rst) {
161                         ip4pkt.tcp.th_flags |= TH_RST;
162                 }
163                 ip4pkt.tcp.th_off   = sizeof(ip4pkt.tcp)/4;
164                 /* this makes it easier to spot in a sniffer */
165                 ip4pkt.tcp.th_win   = htons(1234);
166                 ip4pkt.tcp.th_sum   = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
167
168                 /* open a raw socket to send this segment from */
169                 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
170                 if (s == -1) {
171                         DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
172                                  strerror(errno)));
173                         return -1;
174                 }
175
176                 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
177                 if (ret != 0) {
178                         DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
179                                  strerror(errno)));
180                         close(s);
181                         return -1;
182                 }
183
184                 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
185                              (const struct sockaddr *)&dest->ip,
186                              sizeof(dest->ip));
187                 saved_errno = errno;
188                 close(s);
189                 if (ret != sizeof(ip4pkt)) {
190                         DEBUG(DEBUG_ERR,
191                               ("Failed sendto (%s)\n", strerror(saved_errno)));
192                         return -1;
193                 }
194                 break;
195         case AF_INET6:
196                 ZERO_STRUCT(ip6pkt);
197                 ip6pkt.ip6.ip6_vfc  = 0x60;
198                 ip6pkt.ip6.ip6_plen = htons(20);
199                 ip6pkt.ip6.ip6_nxt  = IPPROTO_TCP;
200                 ip6pkt.ip6.ip6_hlim = 64;
201                 ip6pkt.ip6.ip6_src  = src->ip6.sin6_addr;
202                 ip6pkt.ip6.ip6_dst  = dest->ip6.sin6_addr;
203
204                 ip6pkt.tcp.th_sport = src->ip6.sin6_port;
205                 ip6pkt.tcp.th_dport = dest->ip6.sin6_port;
206                 ip6pkt.tcp.th_seq   = seq;
207                 ip6pkt.tcp.th_ack   = ack;
208                 ip6pkt.tcp.th_flags = 0;
209                 ip6pkt.tcp.th_flags |= TH_ACK;
210                 if (rst) {
211                         ip6pkt.tcp.th_flags |= TH_RST;
212                 }
213                 ip6pkt.tcp.th_off   = sizeof(ip6pkt.tcp)/4;
214                 /* this makes it easier to spot in a sniffer */
215                 ip6pkt.tcp.th_win   = htons(1234);
216                 ip6pkt.tcp.th_sum   = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
217
218                 s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
219                 if (s == -1) {
220                         DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
221                         return -1;
222
223                 }
224                 /* sendto() don't like if the port is set and the socket is
225                    in raw mode.
226                 */
227                 tmpdest = discard_const(dest);
228                 tmpport = tmpdest->ip6.sin6_port;
229
230                 tmpdest->ip6.sin6_port = 0;
231                 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
232                              (const struct sockaddr *)&dest->ip6,
233                              sizeof(dest->ip6));
234                 saved_errno = errno;
235                 tmpdest->ip6.sin6_port = tmpport;
236                 close(s);
237
238                 if (ret != sizeof(ip6pkt)) {
239                         DEBUG(DEBUG_ERR,
240                               ("Failed sendto (%s)\n", strerror(saved_errno)));
241                         return -1;
242                 }
243                 break;
244
245         default:
246                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
247                 return -1;
248         }
249
250         return 0;
251 }
252
253 /* 
254    This function is used to open a raw socket to capture from
255  */
256 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
257 {
258         pcap_t *pt;
259
260         pt=pcap_open_live(iface, 100, 0, 0, NULL);
261         if (pt == NULL) {
262                 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
263                 return -1;
264         }
265         *((pcap_t **)private_data) = pt;
266
267         return pcap_fileno(pt);
268 }
269
270 /* This function is used to close the capture socket
271  */
272 int ctdb_sys_close_capture_socket(void *private_data)
273 {
274         pcap_t *pt = (pcap_t *)private_data;
275         pcap_close(pt);
276         return 0;
277 }
278
279
280 /*
281   called when the raw socket becomes readable
282  */
283 int ctdb_sys_read_tcp_packet(int s, void *private_data, 
284                              ctdb_sock_addr *src, ctdb_sock_addr *dst,
285                              uint32_t *ack_seq, uint32_t *seq,
286                              int *rst, uint16_t *window)
287 {
288         int ret;
289 #define RCVPKTSIZE 100
290         char pkt[RCVPKTSIZE];
291         struct ether_header *eth;
292         struct ip *ip;
293         struct ip6_hdr *ip6;
294         struct tcphdr *tcp;
295
296         ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
297         if (ret < sizeof(*eth)+sizeof(*ip)) {
298                 return -1;
299         }
300
301         ZERO_STRUCTP(src);
302         ZERO_STRUCTP(dst);
303
304         /* Ethernet */
305         eth = (struct ether_header *)pkt;
306
307         /* we want either IPv4 or IPv6 */
308         if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
309                 /* IP */
310                 ip = (struct ip *)(eth+1);
311
312                 /* We only want IPv4 packets */
313                 if (ip->ip_v != 4) {
314                         return -1;
315                 }
316                 /* Dont look at fragments */
317                 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
318                         return -1;
319                 }
320                 /* we only want TCP */
321                 if (ip->ip_p != IPPROTO_TCP) {
322                         return -1;
323                 }
324
325                 /* make sure its not a short packet */
326                 if (offsetof(struct tcphdr, th_ack) + 4 + 
327                     (ip->ip_hl*4) + sizeof(*eth) > ret) {
328                         return -1;
329                 }
330                 /* TCP */
331                 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
332
333                 /* tell the caller which one we've found */
334                 src->ip.sin_family      = AF_INET;
335                 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
336                 src->ip.sin_port        = tcp->th_sport;
337                 dst->ip.sin_family      = AF_INET;
338                 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
339                 dst->ip.sin_port        = tcp->th_dport;
340                 *ack_seq                = tcp->th_ack;
341                 *seq                    = tcp->th_seq;
342                 if (window != NULL) {
343                         *window = tcp->th_win;
344                 }
345                 if (rst != NULL) {
346                         *rst = tcp->th_flags & TH_RST;
347                 }
348
349                 return 0;
350         } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
351                 /* IP6 */
352                 ip6 = (struct ip6_hdr *)(eth+1);
353
354                 /* we only want TCP */
355                 if (ip6->ip6_nxt != IPPROTO_TCP) {
356                         return -1;
357                 }
358
359                 /* TCP */
360                 tcp = (struct tcphdr *)(ip6+1);
361
362                 /* tell the caller which one we've found */
363                 src->ip6.sin6_family = AF_INET6;
364                 src->ip6.sin6_port   = tcp->th_sport;
365                 src->ip6.sin6_addr   = ip6->ip6_src;
366
367                 dst->ip6.sin6_family = AF_INET6;
368                 dst->ip6.sin6_port   = tcp->th_dport;
369                 dst->ip6.sin6_addr   = ip6->ip6_dst;
370
371                 *ack_seq             = tcp->th_ack;
372                 *seq                 = tcp->th_seq;
373                 if (window != NULL) {
374                         *window = tcp->th_win;
375                 }
376                 if (rst != NULL) {
377                         *rst = tcp->th_flags & TH_RST;
378                 }
379
380                 return 0;
381         }
382
383         return -1;
384 }
385
386 bool ctdb_sys_check_iface_exists(const char *iface)
387 {
388         /* FIXME FreeBSD: Interface always considered present */
389         return true;
390 }
391
392 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
393 {
394         /* FIXME FreeBSD: get_peer_pid not implemented */
395         return 1;
396 }