merge from tridge
[vlendec/samba-autobuild/.git] / ctdb / common / system.c
1 /* 
2    ctdb recovery code
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 <net/ethernet.h>
28 #include <net/if_arp.h>
29
30
31
32 /*
33   send gratuitous arp reply after we have taken over an ip address
34
35   saddr is the address we are trying to claim
36   iface is the interface name we will be using to claim the address
37  */
38 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface)
39 {
40         int s, ret;
41         struct sockaddr sa;
42         struct ether_header *eh;
43         struct arphdr *ah;
44         struct ifreq if_hwaddr;
45         unsigned char buffer[64]; /*minimum eth frame size */
46         char *ptr;
47
48         /* for now, we only handle AF_INET addresses */
49         if (saddr->sin_family != AF_INET) {
50                 DEBUG(0,(__location__ " not an ipv4 address (family is %u)\n", saddr->sin_family));
51                 return -1;
52         }
53
54         s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
55         if (s == -1){
56                 DEBUG(0,(__location__ " failed to open raw socket\n"));
57                 return -1;
58         }
59
60         /* get the mac address */
61         strcpy(if_hwaddr.ifr_name, iface);
62         ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
63         if ( ret < 0 ) {
64                 close(s);
65                 DEBUG(0,(__location__ " ioctl failed\n"));
66                 return -1;
67         }
68         if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
69                 DEBUG(3,("Ignoring loopback arp request\n"));
70                 close(s);
71                 return 0;
72         }
73         if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
74                 close(s);
75                 errno = EINVAL;
76                 DEBUG(0,(__location__ " not an ethernet address family (0x%x)\n",
77                          if_hwaddr.ifr_hwaddr.sa_family));
78                 return -1;
79         }
80
81
82         memset(buffer, 0 , 64);
83         eh = (struct ether_header *)buffer;
84         memset(eh->ether_dhost, 0xff, ETH_ALEN);
85         memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
86         eh->ether_type = htons(ETHERTYPE_ARP);
87
88         ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
89         ah->ar_hrd = htons(ARPHRD_ETHER);
90         ah->ar_pro = htons(ETH_P_IP);
91         ah->ar_hln = ETH_ALEN;
92         ah->ar_pln = 4;
93
94         /* send a gratious arp */
95         ah->ar_op  = htons(ARPOP_REQUEST);
96         ptr = (char *)&ah[1];
97         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
98         ptr+=ETH_ALEN;
99         memcpy(ptr, &saddr->sin_addr, 4);         
100         ptr+=4;
101         memset(ptr, 0, ETH_ALEN); 
102         ptr+=ETH_ALEN;
103         memcpy(ptr, &saddr->sin_addr, 4);         
104         ptr+=4;
105
106         strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
107         ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
108         if (ret < 0 ){
109                 close(s);
110                 DEBUG(0,(__location__ " failed sendto\n"));
111                 return -1;
112         }
113
114         /* send unsolicited arp reply broadcast */
115         ah->ar_op  = htons(ARPOP_REPLY);
116         ptr = (char *)&ah[1];
117         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
118         ptr+=ETH_ALEN;
119         memcpy(ptr, &saddr->sin_addr, 4);         
120         ptr+=4;
121         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
122         ptr+=ETH_ALEN;
123         memcpy(ptr, &saddr->sin_addr, 4);         
124         ptr+=4;
125
126         strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
127         ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
128         if (ret < 0 ){
129                 DEBUG(0,(__location__ " failed sendto\n"));
130                 return -1;
131         }
132
133         close(s);
134         return 0;
135 }
136
137
138 /*
139   uint16 checksum for n bytes
140  */
141 static uint32_t uint16_checksum(uint16_t *data, size_t n)
142 {
143         uint32_t sum=0;
144         while (n>=2) {
145                 sum += (uint32_t)ntohs(*data);
146                 data++;
147                 n -= 2;
148         }
149         if (n == 1) {
150                 sum += (uint32_t)ntohs(*(uint8_t *)data);
151         }
152         return sum;
153 }
154
155 /*
156   simple TCP checksum - assumes data is multiple of 2 bytes long
157  */
158 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
159 {
160         uint32_t sum = uint16_checksum(data, n);
161         uint16_t sum2;
162         sum += uint16_checksum((uint16_t *)&ip->saddr, sizeof(ip->saddr));
163         sum += uint16_checksum((uint16_t *)&ip->daddr, sizeof(ip->daddr));
164         sum += ip->protocol + n;
165         sum = (sum & 0xFFFF) + (sum >> 16);
166         sum = (sum & 0xFFFF) + (sum >> 16);
167         sum2 = htons(sum);
168         sum2 = ~sum2;
169         if (sum2 == 0) {
170                 return 0xFFFF;
171         }
172         return sum2;
173 }
174
175 /*
176   Send tcp segment from the specified IP/port to the specified
177   destination IP/port. 
178
179   This is used to trigger the receiving host into sending its own ACK,
180   which should trigger early detection of TCP reset by the client
181   after IP takeover
182
183   This can also be used to send RST segments (if rst is true) and also
184   if correct seq and ack numbers are provided.
185  */
186 int ctdb_sys_send_tcp(const struct sockaddr_in *dest, 
187                       const struct sockaddr_in *src,
188                       uint32_t seq, uint32_t ack, int rst)
189 {
190         int s, ret;
191         uint32_t one = 1;
192         struct {
193                 struct iphdr ip;
194                 struct tcphdr tcp;
195         } pkt;
196
197         /* for now, we only handle AF_INET addresses */
198         if (src->sin_family != AF_INET || dest->sin_family != AF_INET) {
199                 DEBUG(0,(__location__ " not an ipv4 address\n"));
200                 return -1;
201         }
202
203         s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
204         if (s == -1) {
205                 DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
206                          strerror(errno)));
207                 return -1;
208         }
209
210         ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
211         if (ret != 0) {
212                 DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
213                          strerror(errno)));
214                 close(s);
215                 return -1;
216         }
217
218         ZERO_STRUCT(pkt);
219         pkt.ip.version  = 4;
220         pkt.ip.ihl      = sizeof(pkt.ip)/4;
221         pkt.ip.tot_len  = htons(sizeof(pkt));
222         pkt.ip.ttl      = 255;
223         pkt.ip.protocol = IPPROTO_TCP;
224         pkt.ip.saddr    = src->sin_addr.s_addr;
225         pkt.ip.daddr    = dest->sin_addr.s_addr;
226         pkt.ip.check    = 0;
227
228         pkt.tcp.source   = src->sin_port;
229         pkt.tcp.dest     = dest->sin_port;
230         pkt.tcp.seq      = seq;
231         pkt.tcp.ack_seq  = ack;
232         pkt.tcp.ack      = 1;
233         if (rst) {
234                 pkt.tcp.rst      = 1;
235         }
236         pkt.tcp.doff     = sizeof(pkt.tcp)/4;
237         pkt.tcp.window   = htons(1234);
238         pkt.tcp.check    = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
239
240         ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
241         if (ret != sizeof(pkt)) {
242                 DEBUG(0,(__location__ " failed sendto (%s)\n", strerror(errno)));
243                 close(s);
244                 return -1;
245         }
246
247         close(s);
248         return 0;
249 }
250
251
252 /*
253   see if we currently have an interface with the given IP
254
255   we try to bind to it, and if that fails then we don't have that IP
256   on an interface
257  */
258 bool ctdb_sys_have_ip(const char *ip)
259 {
260         struct sockaddr_in sin;
261         int s;
262         int ret;
263
264         sin.sin_port = 0;
265         inet_aton(ip, &sin.sin_addr);
266         sin.sin_family = AF_INET;
267         s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
268         if (s == -1) {
269                 return false;
270         }
271         ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
272         close(s);
273         return ret == 0;
274 }
275
276 static void ctdb_wait_handler(struct event_context *ev, struct timed_event *te, 
277                               struct timeval yt, void *p)
278 {
279         uint32_t *timed_out = (uint32_t *)p;
280         (*timed_out) = 1;
281 }
282
283 /* This function is used to kill (RST) the specified tcp connection.
284
285    This function is not asynchronous and will block until the operation
286    was successful or it timesout.
287  */
288 int ctdb_sys_kill_tcp(struct event_context *ev,
289                       const struct sockaddr_in *dst, 
290                       const struct sockaddr_in *src)
291 {
292         int s, ret;
293         uint32_t timedout;
294         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
295 #define RCVPKTSIZE 100
296         char pkt[RCVPKTSIZE];
297         struct ether_header *eth;
298         struct iphdr *ip;
299         struct tcphdr *tcp;
300
301         /* Open a socket to capture all traffic */
302         s=socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
303         if (s == -1){
304                 DEBUG(0,(__location__ " failed to open raw socket\n"));
305                 return -1;
306         }
307
308         /* We wait for up to 1 second for the ACK coming back */
309         timedout = 0;
310         event_add_timed(ev, tmp_ctx, timeval_current_ofs(1, 0), ctdb_wait_handler, &timedout);
311
312         /* Send a tickle ack to probe what the real seq/ack numbers are */
313         ctdb_sys_send_tcp(dst, src, 0, 0, 0);
314
315         /* Wait until we either time out or we succeeds in sending the RST */
316         while (timedout==0) {
317                 event_loop_once(ev);
318
319                 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
320                 if (ret < sizeof(*eth)+sizeof(*ip)) {
321                         continue;
322                 }
323
324                 /* Ethernet */
325                 eth = (struct ether_header *)pkt;
326                 /* We only want IP packets */
327                 if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
328                         continue;
329                 }
330         
331                 /* IP */
332                 ip = (struct iphdr *)(eth+1);
333                 /* We only want IPv4 packets */
334                 if (ip->version != 4) {
335                         continue;
336                 }
337                 /* Dont look at fragments */
338                 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
339                         continue;
340                 }
341                 /* we only want TCP */
342                 if (ip->protocol != IPPROTO_TCP) {
343                         continue;
344                 }
345
346                 /* We only want packets sent from the guy we tickled */
347                 if (ip->saddr != dst->sin_addr.s_addr) {
348                         continue;
349                 }
350                 /* We only want packets sent to us */
351                 if (ip->daddr != src->sin_addr.s_addr) {
352                         continue;
353                 }
354
355                 /* make sure its not a short packet */
356                 if (offsetof(struct tcphdr, ack_seq) + 4 + 
357                     (ip->ihl*4) + sizeof(*eth) > ret) {
358                         continue;
359                 }
360
361                 /* TCP */
362                 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
363                 
364                 /* We only want replies from the port we tickled */
365                 if (tcp->source != dst->sin_port) {
366                         continue;
367                 }
368                 if (tcp->dest != src->sin_port) {
369                         continue;
370                 }
371
372                 ctdb_sys_send_tcp(dst, src, tcp->ack_seq, tcp->seq, 1);
373
374                 close(s);
375                 talloc_free(tmp_ctx);
376
377                 return 0;
378         }
379
380         close(s);
381         talloc_free(tmp_ctx);
382         DEBUG(0,(__location__ " timedout waiting for tickle ack reply\n"));
383
384         return -1;
385 }