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"
26 #include "../include/ctdb_private.h"
27 #include <netinet/if_ether.h>
28 #include <netinet/ip6.h>
29 #include <net/if_arp.h>
30 #include <sys/ndd_var.h>
31 #include <sys/kinfo.h>
37 This function is no longer used and its code should be moved into
38 send tcp packet after that function has been enhanced to do ipv6 as well.
40 /* This function is used to open a raw socket to send tickles from
42 int ctdb_sys_open_sending_socket(void)
47 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
49 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
54 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
56 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
70 uint16 checksum for n bytes
72 static uint32_t uint16_checksum(uint16_t *data, size_t n)
76 sum += (uint32_t)ntohs(*data);
81 sum += (uint32_t)ntohs(*(uint8_t *)data);
87 simple TCP checksum - assumes data is multiple of 2 bytes long
89 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
91 uint32_t sum = uint16_checksum(data, n);
94 sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
95 sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
97 sum = (sum & 0xFFFF) + (sum >> 16);
98 sum = (sum & 0xFFFF) + (sum >> 16);
108 Send tcp segment from the specified IP/port to the specified
111 This is used to trigger the receiving host into sending its own ACK,
112 which should trigger early detection of TCP reset by the client
115 This can also be used to send RST segments (if rst is true) and also
116 if correct seq and ack numbers are provided.
118 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
119 const ctdb_sock_addr *src,
120 uint32_t seq, uint32_t ack, int rst)
125 ctdb_sock_addr *tmpdest;
133 /* for now, we only handle AF_INET addresses */
134 if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
135 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
141 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
143 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
148 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
150 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
157 set_close_on_exec(s);
159 memset(&ip4pkt, 0, sizeof(ip4pkt));
161 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
162 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
163 ip4pkt.ip.ip_ttl = 255;
164 ip4pkt.ip.ip_p = IPPROTO_TCP;
165 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
166 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
167 ip4pkt.ip.ip_sum = 0;
169 ip4pkt.tcp.th_sport = src->ip.sin_port;
170 ip4pkt.tcp.th_dport = dest->ip.sin_port;
171 ip4pkt.tcp.th_seq = seq;
172 ip4pkt.tcp.th_ack = ack;
173 ip4pkt.tcp.th_flags = TH_ACK;
175 ip4pkt.tcp.th_flags = TH_RST;
177 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
178 ip4pkt.tcp.th_win = htons(1234);
179 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
181 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
182 if (ret != sizeof(ip4pkt)) {
183 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
192 see if we currently have an interface with the given IP
194 we try to bind to it, and if that fails then we don't have that IP
197 bool ctdb_sys_have_ip(ctdb_sock_addr *addr)
202 addr->ip.sin_port = 0;
203 s = socket(addr->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
207 ret = bind(s, (struct sockaddr *)addr, sizeof(ctdb_sock_addr));
215 /* This function is used to open a raw socket to capture from
217 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
221 pt=pcap_open_live(iface, 100, 0, 0, NULL);
223 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
226 *((pcap_t **)private_data) = pt;
228 return pcap_fileno(pt);
232 /* This function is used to close the capture socket
234 int ctdb_sys_close_capture_socket(void *private_data)
236 pcap_t *pt = (pcap_t *)private_data;
244 send gratuitous arp reply after we have taken over an ip address
246 saddr is the address we are trying to claim
247 iface is the interface name we will be using to claim the address
249 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
251 /* We dont do grat arp on aix yet */
258 get ethernet MAC address on AIX
260 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
263 struct kinfo_ndd *ndd;
266 ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
272 ndd = (struct kinfo_ndd *)malloc(ksize);
278 if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
283 count= ksize/sizeof(struct kinfo_ndd);
284 for (i=0;i<count;i++) {
285 if ( (ndd[i].ndd_type != NDD_ETHER)
286 && (ndd[i].ndd_type != NDD_ISO88023) ) {
289 if (ndd[i].ndd_addrlen != 6) {
292 if (!(ndd[i].ndd_flags&NDD_UP)) {
295 if ( strcmp(device_name, ndd[i].ndd_name)
296 && strcmp(device_name, ndd[i].ndd_alias) ) {
299 memcpy(mac, ndd[i].ndd_addr, 6);
308 int ctdb_sys_read_tcp_packet(int s, void *private_data,
309 ctdb_sock_addr *src, ctdb_sock_addr *dst,
310 uint32_t *ack_seq, uint32_t *seq)
313 struct ether_header *eth;
317 struct ctdb_killtcp_connection *conn;
318 struct pcap_pkthdr pkthdr;
319 const u_char *buffer;
320 pcap_t *pt = (pcap_t *)private_data;
322 buffer=pcap_next(pt, &pkthdr);
328 eth = (struct ether_header *)buffer;
330 /* we want either IPv4 or IPv6 */
331 if (eth->ether_type == htons(ETHERTYPE_IP)) {
333 ip = (struct ip *)(eth+1);
335 /* We only want IPv4 packets */
339 /* Dont look at fragments */
340 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
343 /* we only want TCP */
344 if (ip->ip_p != IPPROTO_TCP) {
348 /* make sure its not a short packet */
349 if (offsetof(struct tcphdr, th_ack) + 4 +
350 (ip->ip_hl*4) > ret) {
354 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
356 /* tell the caller which one we've found */
357 src->ip.sin_family = AF_INET;
358 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
359 src->ip.sin_port = tcp->th_sport;
360 dst->ip.sin_family = AF_INET;
361 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
362 dst->ip.sin_port = tcp->th_dport;
363 *ack_seq = tcp->th_ack;
368 #ifndef ETHERTYPE_IP6
369 #define ETHERTYPE_IP6 0x86dd
371 } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
373 ip6 = (struct ip6_hdr *)(eth+1);
375 /* we only want TCP */
376 if (ip6->ip6_nxt != IPPROTO_TCP) {
381 tcp = (struct tcphdr *)(ip6+1);
383 /* tell the caller which one we've found */
384 src->ip6.sin6_family = AF_INET6;
385 src->ip6.sin6_port = tcp->th_sport;
386 src->ip6.sin6_addr = ip6->ip6_src;
388 dst->ip6.sin6_family = AF_INET6;
389 dst->ip6.sin6_port = tcp->th_dport;
390 dst->ip6.sin6_addr = ip6->ip6_dst;
392 *ack_seq = tcp->th_ack;