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