Add a missing include
[ambi/samba-autobuild/.git] / ctdb / common / system_linux.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
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/network.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
25 #include "../include/ctdb_private.h"
26 #include "lib/events/events.h"
27 #include <netinet/if_ether.h>
28 #include <netinet/ip6.h>
29 #include <net/if_arp.h>
30
31
32
33 /*
34   send gratuitous arp reply after we have taken over an ip address
35
36   saddr is the address we are trying to claim
37   iface is the interface name we will be using to claim the address
38  */
39 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface)
40 {
41         int s, ret;
42         struct sockaddr sa;
43         struct ether_header *eh;
44         struct arphdr *ah;
45         struct ifreq if_hwaddr;
46         unsigned char buffer[64]; /*minimum eth frame size */
47         char *ptr;
48
49         ZERO_STRUCT(sa);
50
51         /* for now, we only handle AF_INET addresses */
52         if (saddr->sin_family != AF_INET) {
53                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address (family is %u)\n", saddr->sin_family));
54                 return -1;
55         }
56
57         s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
58         if (s == -1){
59                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
60                 return -1;
61         }
62
63         /* get the mac address */
64         strcpy(if_hwaddr.ifr_name, iface);
65         ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
66         if ( ret < 0 ) {
67                 close(s);
68                 DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
69                 return -1;
70         }
71         if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
72                 DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
73                 close(s);
74                 return 0;
75         }
76         if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
77                 close(s);
78                 errno = EINVAL;
79                 DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
80                          if_hwaddr.ifr_hwaddr.sa_family));
81                 return -1;
82         }
83
84
85         memset(buffer, 0 , 64);
86         eh = (struct ether_header *)buffer;
87         memset(eh->ether_dhost, 0xff, ETH_ALEN);
88         memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
89         eh->ether_type = htons(ETHERTYPE_ARP);
90
91         ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
92         ah->ar_hrd = htons(ARPHRD_ETHER);
93         ah->ar_pro = htons(ETH_P_IP);
94         ah->ar_hln = ETH_ALEN;
95         ah->ar_pln = 4;
96
97         /* send a gratious arp */
98         ah->ar_op  = htons(ARPOP_REQUEST);
99         ptr = (char *)&ah[1];
100         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
101         ptr+=ETH_ALEN;
102         memcpy(ptr, &saddr->sin_addr, 4);         
103         ptr+=4;
104         memset(ptr, 0, ETH_ALEN); 
105         ptr+=ETH_ALEN;
106         memcpy(ptr, &saddr->sin_addr, 4);         
107         ptr+=4;
108
109         strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
110         ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
111         if (ret < 0 ){
112                 close(s);
113                 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
114                 return -1;
115         }
116
117         /* send unsolicited arp reply broadcast */
118         ah->ar_op  = htons(ARPOP_REPLY);
119         ptr = (char *)&ah[1];
120         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
121         ptr+=ETH_ALEN;
122         memcpy(ptr, &saddr->sin_addr, 4);         
123         ptr+=4;
124         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
125         ptr+=ETH_ALEN;
126         memcpy(ptr, &saddr->sin_addr, 4);         
127         ptr+=4;
128
129         strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
130         ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
131         if (ret < 0 ){
132                 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
133                 return -1;
134         }
135
136         close(s);
137         return 0;
138 }
139
140
141 /*
142   uint16 checksum for n bytes
143  */
144 static uint32_t uint16_checksum(uint16_t *data, size_t n)
145 {
146         uint32_t sum=0;
147         while (n>=2) {
148                 sum += (uint32_t)ntohs(*data);
149                 data++;
150                 n -= 2;
151         }
152         if (n == 1) {
153                 sum += (uint32_t)ntohs(*(uint8_t *)data);
154         }
155         return sum;
156 }
157
158 /*
159   simple TCP checksum - assumes data is multiple of 2 bytes long
160  */
161 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
162 {
163         uint32_t sum = uint16_checksum(data, n);
164         uint16_t sum2;
165         sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
166                                sizeof(ip->saddr));
167         sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
168                                sizeof(ip->daddr));
169         sum += ip->protocol + n;
170         sum = (sum & 0xFFFF) + (sum >> 16);
171         sum = (sum & 0xFFFF) + (sum >> 16);
172         sum2 = htons(sum);
173         sum2 = ~sum2;
174         if (sum2 == 0) {
175                 return 0xFFFF;
176         }
177         return sum2;
178 }
179
180 /*
181   calculate the tcp checksum for tcp over ipv6
182 */
183 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
184 {
185         uint32_t sum = uint16_checksum(data, n);
186         uint16_t sum2;
187
188         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
189         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
190         sum += ip6->ip6_plen;
191         sum += ip6->ip6_nxt;
192                         
193         sum = (sum & 0xFFFF) + (sum >> 16);
194         sum = (sum & 0xFFFF) + (sum >> 16);
195         sum2 = htons(sum);
196         sum2 = ~sum2;
197         if (sum2 == 0) {
198                 return 0xFFFF;
199         }
200         return sum2;
201 }
202
203 /*
204   Send tcp segment from the specified IP/port to the specified
205   destination IP/port. 
206
207   This is used to trigger the receiving host into sending its own ACK,
208   which should trigger early detection of TCP reset by the client
209   after IP takeover
210
211   This can also be used to send RST segments (if rst is true) and also
212   if correct seq and ack numbers are provided.
213  */
214 int ctdb_sys_send_tcp(int s,
215                       const struct sockaddr_in *dest, 
216                       const struct sockaddr_in *src,
217                       uint32_t seq, uint32_t ack, int rst)
218 {
219         int ret;
220         struct {
221                 struct iphdr ip;
222                 struct tcphdr tcp;
223         } pkt;
224
225         /* for now, we only handle AF_INET addresses */
226         if (src->sin_family != AF_INET || dest->sin_family != AF_INET) {
227                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
228                 return -1;
229         }
230
231         ZERO_STRUCT(pkt);
232         pkt.ip.version  = 4;
233         pkt.ip.ihl      = sizeof(pkt.ip)/4;
234         pkt.ip.tot_len  = htons(sizeof(pkt));
235         pkt.ip.ttl      = 255;
236         pkt.ip.protocol = IPPROTO_TCP;
237         pkt.ip.saddr    = src->sin_addr.s_addr;
238         pkt.ip.daddr    = dest->sin_addr.s_addr;
239         pkt.ip.check    = 0;
240
241         pkt.tcp.source   = src->sin_port;
242         pkt.tcp.dest     = dest->sin_port;
243         pkt.tcp.seq      = seq;
244         pkt.tcp.ack_seq  = ack;
245         pkt.tcp.ack      = 1;
246         if (rst) {
247                 pkt.tcp.rst      = 1;
248         }
249         pkt.tcp.doff     = sizeof(pkt.tcp)/4;
250         pkt.tcp.window   = htons(1234); /* this makes it easier to spot in a sniffer */
251         pkt.tcp.check    = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
252
253         ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
254         if (ret != sizeof(pkt)) {
255                 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
256                 return -1;
257         }
258
259         return 0;
260 }
261
262
263 /*
264   see if we currently have an interface with the given IP
265
266   we try to bind to it, and if that fails then we don't have that IP
267   on an interface
268
269   ifname, if non-NULL, will return the name of the interface this ip is tied to
270  */
271 bool ctdb_sys_have_ip(struct sockaddr_in ip)
272 {
273         int s;
274         int ret;
275
276         ip.sin_port = 0;
277         s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
278         if (s == -1) {
279                 return false;
280         }
281         ret = bind(s, (struct sockaddr *)&ip, sizeof(ip));
282
283         close(s);
284         return ret == 0;
285 }
286
287 /* 
288    This function is used to open a raw socket to capture from
289  */
290 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
291 {
292         int s;
293
294         /* Open a socket to capture all traffic */
295         s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
296         if (s == -1) {
297                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
298                 return -1;
299         }
300
301         set_nonblocking(s);
302         set_close_on_exec(s);
303
304         return s;
305 }
306
307 /* 
308    This function is used to do any additional cleanup required when closing
309    a capture socket.
310    Note that the socket itself is closed automatically in the caller.
311  */
312 int ctdb_sys_close_capture_socket(void *private_data)
313 {
314         return 0;
315 }
316
317 /* 
318    This function is used to open a raw socket to send tickles from
319  */
320 int ctdb_sys_open_sending_socket(void)
321 {
322         int s, ret;
323         uint32_t one = 1;
324
325         s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
326         if (s == -1) {
327                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
328                          strerror(errno)));
329                 return -1;
330         }
331
332         ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
333         if (ret != 0) {
334                 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
335                          strerror(errno)));
336                 close(s);
337                 return -1;
338         }
339
340         set_nonblocking(s);
341         set_close_on_exec(s);
342
343         return s;
344 }
345
346 /*
347   called when the raw socket becomes readable
348  */
349 int ctdb_sys_read_tcp_packet(int s, void *private_data, 
350                         struct sockaddr_in *src, struct sockaddr_in *dst,
351                         uint32_t *ack_seq, uint32_t *seq)
352 {
353         int ret;
354 #define RCVPKTSIZE 100
355         char pkt[RCVPKTSIZE];
356         struct ether_header *eth;
357         struct iphdr *ip;
358         struct tcphdr *tcp;
359
360         ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
361         if (ret < sizeof(*eth)+sizeof(*ip)) {
362                 return -1;
363         }
364
365         /* Ethernet */
366         eth = (struct ether_header *)pkt;
367
368         /* We only want IP packets */
369         if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
370                 return -1;
371         }
372         
373         /* IP */
374         ip = (struct iphdr *)(eth+1);
375
376         /* We only want IPv4 packets */
377         if (ip->version != 4) {
378                 return -1;
379         }
380         /* Dont look at fragments */
381         if ((ntohs(ip->frag_off)&0x1fff) != 0) {
382                 return -1;
383         }
384         /* we only want TCP */
385         if (ip->protocol != IPPROTO_TCP) {
386                 return -1;
387         }
388
389         /* make sure its not a short packet */
390         if (offsetof(struct tcphdr, ack_seq) + 4 + 
391             (ip->ihl*4) + sizeof(*eth) > ret) {
392                 return -1;
393         }
394
395         /* TCP */
396         tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
397
398         /* tell the caller which one we've found */
399         src->sin_addr.s_addr = ip->saddr;
400         src->sin_port        = tcp->source;
401         dst->sin_addr.s_addr = ip->daddr;
402         dst->sin_port        = tcp->dest;
403         *ack_seq             = tcp->ack_seq;
404         *seq                 = tcp->seq;
405
406         return 0;
407 }
408
409