2 ctdb system specific code to manage raw sockets on aix
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
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.
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.
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/>.
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/wait.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/blocking.h"
30 #include "protocol/protocol.h"
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>
39 #include "common/logging.h"
40 #include "common/system.h"
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.
47 /* This function is used to open a raw socket to send tickles from
49 int ctdb_sys_open_sending_socket(void)
54 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
56 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
61 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
63 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
69 set_blocking(s, false);
77 simple TCP checksum - assumes data is multiple of 2 bytes long
79 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
81 uint32_t sum = uint16_checksum(data, n);
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));
87 sum = (sum & 0xFFFF) + (sum >> 16);
88 sum = (sum & 0xFFFF) + (sum >> 16);
98 Send tcp segment from the specified IP/port to the specified
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
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.
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)
115 ctdb_sock_addr *tmpdest;
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"));
131 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
133 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
138 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
140 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
146 memset(&ip4pkt, 0, sizeof(ip4pkt));
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;
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;
162 ip4pkt.tcp.th_flags = TH_RST;
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);
168 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
169 (struct sockaddr *)dest, sizeof(*dest));
172 if (ret != sizeof(ip4pkt)) {
174 ("Failed sendto (%s)\n", strerror(saved_errno)));
181 /* This function is used to open a raw socket to capture from
183 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
187 pt=pcap_open_live(iface, 100, 0, 0, NULL);
189 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
192 *((pcap_t **)private_data) = pt;
194 return pcap_fileno(pt);
198 /* This function is used to close the capture socket
200 int ctdb_sys_close_capture_socket(void *private_data)
202 pcap_t *pt = (pcap_t *)private_data;
210 send gratuitous arp reply after we have taken over an ip address
212 saddr is the address we are trying to claim
213 iface is the interface name we will be using to claim the address
215 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
217 /* FIXME AIX: We don't do gratuitous arp yet */
224 get ethernet MAC address on AIX
226 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
229 struct kinfo_ndd *ndd;
232 ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
238 ndd = (struct kinfo_ndd *)malloc(ksize);
244 if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
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) ) {
255 if (ndd[i].ndd_addrlen != 6) {
258 if (!(ndd[i].ndd_flags&NDD_UP)) {
261 if ( strcmp(device_name, ndd[i].ndd_name)
262 && strcmp(device_name, ndd[i].ndd_alias) ) {
265 memcpy(mac, ndd[i].ndd_addr, 6);
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)
280 struct ether_header *eth;
284 struct ctdb_killtcp_connection *conn;
285 struct pcap_pkthdr pkthdr;
286 const u_char *buffer;
287 pcap_t *pt = (pcap_t *)private_data;
289 buffer=pcap_next(pt, &pkthdr);
298 eth = (struct ether_header *)buffer;
300 /* we want either IPv4 or IPv6 */
301 if (eth->ether_type == htons(ETHERTYPE_IP)) {
303 ip = (struct ip *)(eth+1);
305 /* We only want IPv4 packets */
309 /* Dont look at fragments */
310 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
313 /* we only want TCP */
314 if (ip->ip_p != IPPROTO_TCP) {
318 /* make sure its not a short packet */
319 if (offsetof(struct tcphdr, th_ack) + 4 +
320 (ip->ip_hl*4) > ret) {
324 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
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;
335 if (window != NULL) {
336 *window = tcp->th_win;
339 *rst = tcp->th_flags & TH_RST;
343 #ifndef ETHERTYPE_IP6
344 #define ETHERTYPE_IP6 0x86dd
346 } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
348 ip6 = (struct ip6_hdr *)(eth+1);
350 /* we only want TCP */
351 if (ip6->ip6_nxt != IPPROTO_TCP) {
356 tcp = (struct tcphdr *)(ip6+1);
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;
363 dst->ip6.sin6_family = AF_INET6;
364 dst->ip6.sin6_port = tcp->th_dport;
365 dst->ip6.sin6_addr = ip6->ip6_dst;
367 *ack_seq = tcp->th_ack;
369 if (window != NULL) {
370 *window = tcp->th_win;
373 *rst = tcp->th_flags & TH_RST;
383 bool ctdb_sys_check_iface_exists(const char *iface)
385 /* FIXME AIX: Interface always considered present */
389 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
391 struct peercred_struct cr;
392 socklen_t crl = sizeof(struct peercred_struct);
394 if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERID, &cr, &crl)) == 0) {