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 <netinet/if_ether.h>
27 #include "../include/ctdb_private.h"
28 #include <sys/ndd_var.h>
29 #include <sys/kinfo.h>
35 This function is no longer used and its code should be moved into
36 send tcp packet after that function has been enhanced to do ipv6 as well.
38 /* This function is used to open a raw socket to send tickles from
40 int ctdb_sys_open_sending_socket(void)
45 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
47 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
52 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
54 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
68 uint16 checksum for n bytes
70 static uint32_t uint16_checksum(uint16_t *data, size_t n)
74 sum += (uint32_t)ntohs(*data);
79 sum += (uint32_t)ntohs(*(uint8_t *)data);
85 simple TCP checksum - assumes data is multiple of 2 bytes long
87 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
89 uint32_t sum = uint16_checksum(data, n);
92 sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
93 sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
95 sum = (sum & 0xFFFF) + (sum >> 16);
96 sum = (sum & 0xFFFF) + (sum >> 16);
106 Send tcp segment from the specified IP/port to the specified
109 This is used to trigger the receiving host into sending its own ACK,
110 which should trigger early detection of TCP reset by the client
113 This can also be used to send RST segments (if rst is true) and also
114 if correct seq and ack numbers are provided.
116 int ctdb_sys_send_tcp(int s,
117 const struct sockaddr_in *dest,
118 const struct sockaddr_in *src,
119 uint32_t seq, uint32_t ack, int rst)
127 /* for now, we only handle AF_INET addresses */
128 if (src->sin_family != AF_INET || dest->sin_family != AF_INET) {
129 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
133 memset(&pkt, 0, sizeof(pkt));
135 pkt.ip.ip_hl = sizeof(pkt.ip)/4;
136 pkt.ip.ip_len = htons(sizeof(pkt));
138 pkt.ip.ip_p = IPPROTO_TCP;
139 pkt.ip.ip_src.s_addr = src->sin_addr.s_addr;
140 pkt.ip.ip_dst.s_addr = dest->sin_addr.s_addr;
143 pkt.tcp.th_sport = src->sin_port;
144 pkt.tcp.th_dport = dest->sin_port;
145 pkt.tcp.th_seq = seq;
146 pkt.tcp.th_ack = ack;
147 pkt.tcp.th_flags = TH_ACK;
149 pkt.tcp.th_flags = TH_RST;
151 pkt.tcp.th_off = sizeof(pkt.tcp)/4;
152 pkt.tcp.th_win = htons(1234);
153 pkt.tcp.th_sum = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
155 ret = sendto(s, &pkt, sizeof(pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
156 if (ret != sizeof(pkt)) {
157 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
166 see if we currently have an interface with the given IP
168 we try to bind to it, and if that fails then we don't have that IP
171 bool ctdb_sys_have_ip(struct sockaddr_in ip)
177 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
181 ret = bind(s, (struct sockaddr *)&ip, sizeof(ip));
189 /* This function is used to open a raw socket to capture from
191 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
195 pt=pcap_open_live(iface, 100, 0, 0, NULL);
197 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
200 *((pcap_t **)private_data) = pt;
202 return pcap_fileno(pt);
206 /* This function is used to close the capture socket
208 int ctdb_sys_close_capture_socket(void *private_data)
210 pcap_t *pt = (pcap_t *)private_data;
218 send gratuitous arp reply after we have taken over an ip address
220 saddr is the address we are trying to claim
221 iface is the interface name we will be using to claim the address
223 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface)
225 /* We dont do grat arp on aix yet */
232 get ethernet MAC address on AIX
234 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
237 struct kinfo_ndd *ndd;
240 ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
246 ndd = (struct kinfo_ndd *)malloc(ksize);
252 if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
257 count= ksize/sizeof(struct kinfo_ndd);
258 for (i=0;i<count;i++) {
259 if ( (ndd[i].ndd_type != NDD_ETHER)
260 && (ndd[i].ndd_type != NDD_ISO88023) ) {
263 if (ndd[i].ndd_addrlen != 6) {
266 if (!(ndd[i].ndd_flags&NDD_UP)) {
269 if ( strcmp(device_name, ndd[i].ndd_name)
270 && strcmp(device_name, ndd[i].ndd_alias) ) {
273 memcpy(mac, ndd[i].ndd_addr, 6);
282 int ctdb_sys_read_tcp_packet(int s, void *private_data,
283 struct sockaddr_in *src, struct sockaddr_in *dst,
284 uint32_t *ack_seq, uint32_t *seq)
287 struct ether_header *eth;
290 struct ctdb_killtcp_connection *conn;
291 struct pcap_pkthdr pkthdr;
292 const u_char *buffer;
293 pcap_t *pt = (pcap_t *)private_data;
295 buffer=pcap_next(pt, &pkthdr);
301 eth = (struct ether_header *)buffer;
303 /* We are only interested in IP packets */
304 if (eth->ether_type != htons(ETHERTYPE_IP)) {
309 ip = (struct ip *)(eth+1);
311 /* We only want IPv4 packets */
315 /* Dont look at fragments */
316 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
319 /* we only want TCP */
320 if (ip->ip_p != IPPROTO_TCP) {
324 /* make sure its not a short packet */
325 if (offsetof(struct tcphdr, th_ack) + 4 +
326 (ip->ip_hl*4) > ret) {
330 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
332 /* tell the caller which one we've found */
333 src->sin_addr.s_addr = ip->ip_src.s_addr;
334 src->sin_port = tcp->th_sport;
335 dst->sin_addr.s_addr = ip->ip_dst.s_addr;
336 dst->sin_port = tcp->th_dport;
337 *ack_seq = tcp->th_ack;