ctdb-common: Improve error handling in run_event
[vlendec/samba-autobuild/.git] / ctdb / common / system_aix.c
1 /* 
2    ctdb system specific code to manage raw sockets on aix
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
22 #include "replace.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/wait.h"
26
27 #include "lib/util/debug.h"
28 #include "lib/util/blocking.h"
29
30 #include "protocol/protocol.h"
31
32 #include <netinet/if_ether.h>
33 #include <netinet/ip6.h>
34 #include <net/if_arp.h>
35 #include <sys/ndd_var.h>
36 #include <sys/kinfo.h>
37 #include <pcap.h>
38
39 #include "common/logging.h"
40 #include "common/system.h"
41
42
43 #if 0
44 This function is no longer used and its code should be moved into
45 send tcp packet   after that function has been enhanced to do ipv6 as well.
46
47 /* This function is used to open a raw socket to send tickles from
48  */
49 int ctdb_sys_open_sending_socket(void)
50 {
51         int s, ret;
52         uint32_t one = 1;
53
54         s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
55         if (s == -1) {
56                 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
57                          strerror(errno)));
58                 return -1;
59         }
60
61         ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
62         if (ret != 0) {
63                 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
64                          strerror(errno)));
65                 close(s);
66                 return -1;
67         }
68
69         set_blocking(s, false);
70         set_close_on_exec(s);
71
72         return s;
73 }
74 #endif
75
76 /*
77   simple TCP checksum - assumes data is multiple of 2 bytes long
78  */
79 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
80 {
81         uint32_t sum = uint16_checksum(data, n);
82         uint16_t sum2;
83
84         sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
85         sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
86         sum += ip->ip_p + n;
87         sum = (sum & 0xFFFF) + (sum >> 16);
88         sum = (sum & 0xFFFF) + (sum >> 16);
89         sum2 = htons(sum);
90         sum2 = ~sum2;
91         if (sum2 == 0) {
92                 return 0xFFFF;
93         }
94         return sum2;
95 }
96
97 /*
98   Send tcp segment from the specified IP/port to the specified
99   destination IP/port. 
100
101   This is used to trigger the receiving host into sending its own ACK,
102   which should trigger early detection of TCP reset by the client
103   after IP takeover
104
105   This can also be used to send RST segments (if rst is true) and also
106   if correct seq and ack numbers are provided.
107  */
108 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
109                       const ctdb_sock_addr *src,
110                       uint32_t seq, uint32_t ack, int rst)
111 {
112         int s;
113         int ret;
114         uint32_t one = 1;
115         ctdb_sock_addr *tmpdest;
116         
117         struct {
118                 struct ip ip;
119                 struct tcphdr tcp;
120         } ip4pkt;
121         int saved_errno;
122
123         /* for now, we only handle AF_INET addresses */
124         if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
125                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
126                 return -1;
127         }
128
129
130
131         s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
132         if (s == -1) {
133                 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
134                          strerror(errno)));
135                 return -1;
136         }
137
138         ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
139         if (ret != 0) {
140                 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
141                          strerror(errno)));
142                 close(s);
143                 return -1;
144         }
145
146         memset(&ip4pkt, 0, sizeof(ip4pkt));
147         ip4pkt.ip.ip_v     = 4;
148         ip4pkt.ip.ip_hl    = sizeof(ip4pkt.ip)/4;
149         ip4pkt.ip.ip_len   = htons(sizeof(ip4pkt));
150         ip4pkt.ip.ip_ttl   = 255;
151         ip4pkt.ip.ip_p     = IPPROTO_TCP;
152         ip4pkt.ip.ip_src.s_addr   = src->ip.sin_addr.s_addr;
153         ip4pkt.ip.ip_dst.s_addr   = dest->ip.sin_addr.s_addr;
154         ip4pkt.ip.ip_sum   = 0;
155
156         ip4pkt.tcp.th_sport   = src->ip.sin_port;
157         ip4pkt.tcp.th_dport     = dest->ip.sin_port;
158         ip4pkt.tcp.th_seq      = seq;
159         ip4pkt.tcp.th_ack    = ack;
160         ip4pkt.tcp.th_flags  = TH_ACK;
161         if (rst) {
162                 ip4pkt.tcp.th_flags      = TH_RST;
163         }
164         ip4pkt.tcp.th_off    = sizeof(ip4pkt.tcp)/4;
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         ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
169                      (struct sockaddr *)dest, sizeof(*dest));
170         saved_errno = errno;
171         close(s);
172         if (ret != sizeof(ip4pkt)) {
173                 DEBUG(DEBUG_ERR,
174                       ("Failed sendto (%s)\n", strerror(saved_errno)));
175                 return -1;
176         }
177
178         return 0;
179 }
180
181 /* This function is used to open a raw socket to capture from
182  */
183 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
184 {
185         pcap_t *pt;
186
187         pt=pcap_open_live(iface, 100, 0, 0, NULL);
188         if (pt == NULL) {
189                 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
190                 return -1;
191         }
192         *((pcap_t **)private_data) = pt;
193
194         return pcap_fileno(pt);
195 }
196
197
198 /* This function is used to close the capture socket
199  */
200 int ctdb_sys_close_capture_socket(void *private_data)
201 {
202         pcap_t *pt = (pcap_t *)private_data;
203         pcap_close(pt);
204         return 0;
205 }
206
207
208
209 /*
210   send gratuitous arp reply after we have taken over an ip address
211
212   saddr is the address we are trying to claim
213   iface is the interface name we will be using to claim the address
214  */
215 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
216 {
217         /* FIXME AIX: We don't do gratuitous arp yet */
218         return -1;
219 }
220
221
222
223 /*
224   get ethernet MAC address on AIX
225  */
226 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
227 {
228         size_t ksize;
229         struct kinfo_ndd *ndd;
230         int count, i;
231
232         ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
233         if (ksize == 0) {
234                 errno = ENOSYS;
235                 return -1;
236         }
237
238         ndd = (struct kinfo_ndd *)malloc(ksize);
239         if (ndd == NULL) {
240                 errno = ENOMEM;
241                 return -1;
242         }
243
244         if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
245                 errno = ENOSYS;
246                 return -1;
247         }
248
249         count= ksize/sizeof(struct kinfo_ndd);
250         for (i=0;i<count;i++) {
251                 if ( (ndd[i].ndd_type != NDD_ETHER) 
252                 &&   (ndd[i].ndd_type != NDD_ISO88023) ) {
253                         continue;
254                 }
255                 if (ndd[i].ndd_addrlen != 6) {
256                         continue;
257                 }
258                 if (!(ndd[i].ndd_flags&NDD_UP)) {
259                         continue;
260                 }
261                 if ( strcmp(device_name, ndd[i].ndd_name)
262                 &&   strcmp(device_name, ndd[i].ndd_alias) ) {
263                         continue;
264                 }
265                 memcpy(mac, ndd[i].ndd_addr, 6);
266                 free(ndd);
267                 return 0;
268         }
269         free(ndd);
270         errno = ENOENT;
271         return -1;
272 }
273
274 int ctdb_sys_read_tcp_packet(int s, void *private_data,
275                              ctdb_sock_addr *src, ctdb_sock_addr *dst,
276                              uint32_t *ack_seq, uint32_t *seq,
277                              int *rst, uint16_t *window)
278 {
279         int ret;
280         struct ether_header *eth;
281         struct ip *ip;
282         struct ip6_hdr *ip6;
283         struct tcphdr *tcp;
284         struct ctdb_killtcp_connection *conn;
285         struct pcap_pkthdr pkthdr;
286         const u_char *buffer;
287         pcap_t *pt = (pcap_t *)private_data;
288
289         buffer=pcap_next(pt, &pkthdr);
290         if (buffer==NULL) {
291                 return -1;
292         }
293
294         ZERO_STRUCTP(src);
295         ZERO_STRUCTP(dst);
296
297         /* Ethernet */
298         eth = (struct ether_header *)buffer;
299
300         /* we want either IPv4 or IPv6 */
301         if (eth->ether_type == htons(ETHERTYPE_IP)) {
302                 /* IP */
303                 ip = (struct ip *)(eth+1);
304
305                 /* We only want IPv4 packets */
306                 if (ip->ip_v != 4) {
307                         return -1;
308                 }
309                 /* Dont look at fragments */
310                 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
311                         return -1;
312                 }
313                 /* we only want TCP */
314                 if (ip->ip_p != IPPROTO_TCP) {
315                         return -1;
316                 }
317
318                 /* make sure its not a short packet */
319                 if (offsetof(struct tcphdr, th_ack) + 4 + 
320                     (ip->ip_hl*4) > ret) {
321                         return -1;
322                 }
323                 /* TCP */
324                 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
325         
326                 /* tell the caller which one we've found */
327                 src->ip.sin_family      = AF_INET;
328                 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
329                 src->ip.sin_port        = tcp->th_sport;
330                 dst->ip.sin_family      = AF_INET;
331                 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
332                 dst->ip.sin_port        = tcp->th_dport;
333                 *ack_seq                = tcp->th_ack;
334                 *seq                    = tcp->th_seq;
335                 if (window != NULL) {
336                         *window = tcp->th_win;
337                 }
338                 if (rst != NULL) {
339                         *rst = tcp->th_flags & TH_RST;
340                 }
341
342                 return 0;
343 #ifndef ETHERTYPE_IP6
344 #define ETHERTYPE_IP6 0x86dd
345 #endif
346         } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
347                         /* IP6 */
348                 ip6 = (struct ip6_hdr *)(eth+1);
349
350                 /* we only want TCP */
351                 if (ip6->ip6_nxt != IPPROTO_TCP) {
352                         return -1;
353                 }
354
355                 /* TCP */
356                 tcp = (struct tcphdr *)(ip6+1);
357
358                 /* tell the caller which one we've found */
359                 src->ip6.sin6_family = AF_INET6;
360                 src->ip6.sin6_port   = tcp->th_sport;
361                 src->ip6.sin6_addr   = ip6->ip6_src;
362
363                 dst->ip6.sin6_family = AF_INET6;
364                 dst->ip6.sin6_port   = tcp->th_dport;
365                 dst->ip6.sin6_addr   = ip6->ip6_dst;
366
367                 *ack_seq             = tcp->th_ack;
368                 *seq                 = tcp->th_seq;
369                 if (window != NULL) {
370                         *window = tcp->th_win;
371                 }
372                 if (rst != NULL) {
373                         *rst = tcp->th_flags & TH_RST;
374                 }
375
376                 return 0;
377         }
378
379         return -1;
380 }
381
382
383 bool ctdb_sys_check_iface_exists(const char *iface)
384 {
385         /* FIXME AIX: Interface always considered present */
386         return true;
387 }
388
389 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
390 {
391         struct peercred_struct cr;
392         socklen_t crl = sizeof(struct peercred_struct);
393         int ret;
394         if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERID, &cr, &crl)) == 0) {
395                 *peer_pid = cr.pid;
396         }
397         return ret;
398 }