2 ctdb system specific code to manage raw sockets on freebsd
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
6 Copyright (C) Marc Dequènes (Duck) 2009
7 Copyright (C) Volker Lendecke 2012
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 This file is a copy of 'common/system_linux.c' adapted for Hurd^W kFreeBSD
24 needs, and inspired by 'common/system_aix.c' for the pcap usage.
28 #include "system/network.h"
29 #include "system/filesys.h"
30 #include "system/wait.h"
31 #include "../include/ctdb_private.h"
32 #include "lib/tevent/tevent.h"
33 #include <net/ethernet.h>
34 #include <netinet/ip6.h>
35 #include <net/if_arp.h>
40 #define ETHERTYPE_IP6 0x86dd
44 calculate the tcp checksum for tcp over ipv6
46 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
52 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
53 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
56 phdr[1] = htonl(ip6->ip6_nxt);
57 sum += uint16_checksum((uint16_t *)phdr, 8);
59 sum += uint16_checksum(data, n);
61 sum = (sum & 0xFFFF) + (sum >> 16);
62 sum = (sum & 0xFFFF) + (sum >> 16);
72 send gratuitous arp reply after we have taken over an ip address
74 saddr is the address we are trying to claim
75 iface is the interface name we will be using to claim the address
77 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
79 /* FIXME We dont do gratuitous arp on Hurd yet */
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);
91 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_src,
93 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_dst,
96 sum = (sum & 0xFFFF) + (sum >> 16);
97 sum = (sum & 0xFFFF) + (sum >> 16);
107 Send tcp segment from the specified IP/port to the specified
110 This is used to trigger the receiving host into sending its own ACK,
111 which should trigger early detection of TCP reset by the client
114 This can also be used to send RST segments (if rst is true) and also
115 if correct seq and ack numbers are provided.
117 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
118 const ctdb_sock_addr *src,
119 uint32_t seq, uint32_t ack, int rst)
125 ctdb_sock_addr *tmpdest;
135 switch (src->ip.sin_family) {
139 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
140 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
141 ip4pkt.ip.ip_ttl = 255;
142 ip4pkt.ip.ip_p = IPPROTO_TCP;
143 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
144 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
145 ip4pkt.ip.ip_sum = 0;
147 ip4pkt.tcp.th_sport = src->ip.sin_port;
148 ip4pkt.tcp.th_dport = dest->ip.sin_port;
149 ip4pkt.tcp.th_seq = seq;
150 ip4pkt.tcp.th_ack = ack;
151 ip4pkt.tcp.th_flags = 0;
152 ip4pkt.tcp.th_flags |= TH_ACK;
154 ip4pkt.tcp.th_flags |= TH_RST;
156 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
157 /* this makes it easier to spot in a sniffer */
158 ip4pkt.tcp.th_win = htons(1234);
159 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
161 /* open a raw socket to send this segment from */
162 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
164 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
169 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
171 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
178 set_close_on_exec(s);
180 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
181 (const struct sockaddr *)&dest->ip,
184 if (ret != sizeof(ip4pkt)) {
185 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
191 ip6pkt.ip6.ip6_vfc = 0x60;
192 ip6pkt.ip6.ip6_plen = htons(20);
193 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
194 ip6pkt.ip6.ip6_hlim = 64;
195 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
196 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
198 ip6pkt.tcp.th_sport = src->ip6.sin6_port;
199 ip6pkt.tcp.th_dport = dest->ip6.sin6_port;
200 ip6pkt.tcp.th_seq = seq;
201 ip6pkt.tcp.th_ack = ack;
202 ip6pkt.tcp.th_flags = 0;
203 ip6pkt.tcp.th_flags |= TH_ACK;
205 ip6pkt.tcp.th_flags |= TH_RST;
207 ip6pkt.tcp.th_off = sizeof(ip6pkt.tcp)/4;
208 /* this makes it easier to spot in a sniffer */
209 ip6pkt.tcp.th_win = htons(1234);
210 ip6pkt.tcp.th_sum = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
212 s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
214 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
218 /* sendto() dont like if the port is set and the socket is
221 tmpdest = discard_const(dest);
222 tmpport = tmpdest->ip6.sin6_port;
224 tmpdest->ip6.sin6_port = 0;
225 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
226 (const struct sockaddr *)&dest->ip6,
228 tmpdest->ip6.sin6_port = tmpport;
231 if (ret != sizeof(ip6pkt)) {
232 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
238 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
246 This function is used to open a raw socket to capture from
248 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
252 pt=pcap_open_live(iface, 100, 0, 0, NULL);
254 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
257 *((pcap_t **)private_data) = pt;
259 return pcap_fileno(pt);
262 /* This function is used to close the capture socket
264 int ctdb_sys_close_capture_socket(void *private_data)
266 pcap_t *pt = (pcap_t *)private_data;
273 called when the raw socket becomes readable
275 int ctdb_sys_read_tcp_packet(int s, void *private_data,
276 ctdb_sock_addr *src, ctdb_sock_addr *dst,
277 uint32_t *ack_seq, uint32_t *seq)
280 #define RCVPKTSIZE 100
281 char pkt[RCVPKTSIZE];
282 struct ether_header *eth;
287 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
288 if (ret < sizeof(*eth)+sizeof(*ip)) {
293 eth = (struct ether_header *)pkt;
295 /* we want either IPv4 or IPv6 */
296 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
298 ip = (struct ip *)(eth+1);
300 /* We only want IPv4 packets */
304 /* Dont look at fragments */
305 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
308 /* we only want TCP */
309 if (ip->ip_p != IPPROTO_TCP) {
313 /* make sure its not a short packet */
314 if (offsetof(struct tcphdr, th_ack) + 4 +
315 (ip->ip_hl*4) + sizeof(*eth) > ret) {
319 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
321 /* tell the caller which one we've found */
322 src->ip.sin_family = AF_INET;
323 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
324 src->ip.sin_port = tcp->th_sport;
325 dst->ip.sin_family = AF_INET;
326 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
327 dst->ip.sin_port = tcp->th_dport;
328 *ack_seq = tcp->th_ack;
332 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
334 ip6 = (struct ip6_hdr *)(eth+1);
336 /* we only want TCP */
337 if (ip6->ip6_nxt != IPPROTO_TCP) {
342 tcp = (struct tcphdr *)(ip6+1);
344 /* tell the caller which one we've found */
345 src->ip6.sin6_family = AF_INET6;
346 src->ip6.sin6_port = tcp->th_sport;
347 src->ip6.sin6_addr = ip6->ip6_src;
349 dst->ip6.sin6_family = AF_INET6;
350 dst->ip6.sin6_port = tcp->th_dport;
351 dst->ip6.sin6_addr = ip6->ip6_dst;
353 *ack_seq = tcp->th_ack;
362 bool ctdb_sys_check_iface_exists(const char *iface)
367 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
369 /* FIXME not implemented */