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
);
295 eth
= (struct ether_header
*)buffer
;
297 /* we want either IPv4 or IPv6 */
298 if (eth
->ether_type
== htons(ETHERTYPE_IP
)) {
300 ip
= (struct ip
*)(eth
+1);
302 /* We only want IPv4 packets */
306 /* Dont look at fragments */
307 if ((ntohs(ip
->ip_off
)&0x1fff) != 0) {
310 /* we only want TCP */
311 if (ip
->ip_p
!= IPPROTO_TCP
) {
315 /* make sure its not a short packet */
316 if (offsetof(struct tcphdr
, th_ack
) + 4 +
317 (ip
->ip_hl
*4) > ret
) {
321 tcp
= (struct tcphdr
*)((ip
->ip_hl
*4) + (char *)ip
);
323 /* tell the caller which one we've found */
324 src
->ip
.sin_family
= AF_INET
;
325 src
->ip
.sin_addr
.s_addr
= ip
->ip_src
.s_addr
;
326 src
->ip
.sin_port
= tcp
->th_sport
;
327 dst
->ip
.sin_family
= AF_INET
;
328 dst
->ip
.sin_addr
.s_addr
= ip
->ip_dst
.s_addr
;
329 dst
->ip
.sin_port
= tcp
->th_dport
;
330 *ack_seq
= tcp
->th_ack
;
332 if (window
!= NULL
) {
333 *window
= tcp
->th_win
;
336 *rst
= tcp
->th_flags
& TH_RST
;
340 #ifndef ETHERTYPE_IP6
341 #define ETHERTYPE_IP6 0x86dd
343 } else if (eth
->ether_type
== htons(ETHERTYPE_IP6
)) {
345 ip6
= (struct ip6_hdr
*)(eth
+1);
347 /* we only want TCP */
348 if (ip6
->ip6_nxt
!= IPPROTO_TCP
) {
353 tcp
= (struct tcphdr
*)(ip6
+1);
355 /* tell the caller which one we've found */
356 src
->ip6
.sin6_family
= AF_INET6
;
357 src
->ip6
.sin6_port
= tcp
->th_sport
;
358 src
->ip6
.sin6_addr
= ip6
->ip6_src
;
360 dst
->ip6
.sin6_family
= AF_INET6
;
361 dst
->ip6
.sin6_port
= tcp
->th_dport
;
362 dst
->ip6
.sin6_addr
= ip6
->ip6_dst
;
364 *ack_seq
= tcp
->th_ack
;
366 if (window
!= NULL
) {
367 *window
= tcp
->th_win
;
370 *rst
= tcp
->th_flags
& TH_RST
;
380 bool ctdb_sys_check_iface_exists(const char *iface
)
382 /* FIXME AIX: Interface always considered present */
386 int ctdb_get_peer_pid(const int fd
, pid_t
*peer_pid
)
388 struct peercred_struct cr
;
389 socklen_t crl
= sizeof(struct peercred_struct
);
391 if ((ret
= getsockopt(fd
, SOL_SOCKET
, SO_PEERID
, &cr
, &crl
)) == 0) {