source: vendor/current/ctdb/common/system_aix.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

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