ctdb-common: Use documented names for protocol family in socket()
[Samba.git] / ctdb / common / system_freebsd.c
blob37e4bae88a16dee26e410bbbd706d19f844cc2ec
1 /*
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.
27 #include "replace.h"
28 #include "system/network.h"
29 #include "system/filesys.h"
30 #include "system/wait.h"
32 #include "lib/util/debug.h"
34 #include "protocol/protocol.h"
36 #include <net/ethernet.h>
37 #include <netinet/ip6.h>
38 #include <net/if_arp.h>
39 #include <pcap.h>
41 #include "common/logging.h"
42 #include "common/system.h"
44 #ifndef ETHERTYPE_IP6
45 #define ETHERTYPE_IP6 0x86dd
46 #endif
49 calculate the tcp checksum for tcp over ipv6
51 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
53 uint32_t phdr[2];
54 uint32_t sum = 0;
55 uint16_t sum2;
57 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
58 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
60 phdr[0] = htonl(n);
61 phdr[1] = htonl(ip6->ip6_nxt);
62 sum += uint16_checksum((uint16_t *)phdr, 8);
64 sum += uint16_checksum(data, n);
66 sum = (sum & 0xFFFF) + (sum >> 16);
67 sum = (sum & 0xFFFF) + (sum >> 16);
68 sum2 = htons(sum);
69 sum2 = ~sum2;
70 if (sum2 == 0) {
71 return 0xFFFF;
73 return sum2;
77 send gratuitous arp reply after we have taken over an ip address
79 saddr is the address we are trying to claim
80 iface is the interface name we will be using to claim the address
82 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
84 /* FIXME FreeBSD: We don't do gratuitous arp yet */
85 return -1;
90 simple TCP checksum - assumes data is multiple of 2 bytes long
92 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
94 uint32_t sum = uint16_checksum(data, n);
95 uint16_t sum2;
96 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_src,
97 sizeof(ip->ip_src));
98 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_dst,
99 sizeof(ip->ip_dst));
100 sum += ip->ip_p + n;
101 sum = (sum & 0xFFFF) + (sum >> 16);
102 sum = (sum & 0xFFFF) + (sum >> 16);
103 sum2 = htons(sum);
104 sum2 = ~sum2;
105 if (sum2 == 0) {
106 return 0xFFFF;
108 return sum2;
112 Send tcp segment from the specified IP/port to the specified
113 destination IP/port.
115 This is used to trigger the receiving host into sending its own ACK,
116 which should trigger early detection of TCP reset by the client
117 after IP takeover
119 This can also be used to send RST segments (if rst is true) and also
120 if correct seq and ack numbers are provided.
122 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
123 const ctdb_sock_addr *src,
124 uint32_t seq, uint32_t ack, int rst)
126 int s;
127 int ret;
128 uint32_t one = 1;
129 uint16_t tmpport;
130 ctdb_sock_addr *tmpdest;
131 struct {
132 struct ip ip;
133 struct tcphdr tcp;
134 } ip4pkt;
135 struct {
136 struct ip6_hdr ip6;
137 struct tcphdr tcp;
138 } ip6pkt;
140 switch (src->ip.sin_family) {
141 case AF_INET:
142 ZERO_STRUCT(ip4pkt);
143 ip4pkt.ip.ip_v = 4;
144 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
145 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
146 ip4pkt.ip.ip_ttl = 255;
147 ip4pkt.ip.ip_p = IPPROTO_TCP;
148 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
149 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
150 ip4pkt.ip.ip_sum = 0;
152 ip4pkt.tcp.th_sport = src->ip.sin_port;
153 ip4pkt.tcp.th_dport = dest->ip.sin_port;
154 ip4pkt.tcp.th_seq = seq;
155 ip4pkt.tcp.th_ack = ack;
156 ip4pkt.tcp.th_flags = 0;
157 ip4pkt.tcp.th_flags |= TH_ACK;
158 if (rst) {
159 ip4pkt.tcp.th_flags |= TH_RST;
161 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
162 /* this makes it easier to spot in a sniffer */
163 ip4pkt.tcp.th_win = htons(1234);
164 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
166 /* open a raw socket to send this segment from */
167 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
168 if (s == -1) {
169 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
170 strerror(errno)));
171 return -1;
174 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
175 if (ret != 0) {
176 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
177 strerror(errno)));
178 close(s);
179 return -1;
182 set_nonblocking(s);
183 set_close_on_exec(s);
185 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
186 (const struct sockaddr *)&dest->ip,
187 sizeof(dest->ip));
188 close(s);
189 if (ret != sizeof(ip4pkt)) {
190 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
191 return -1;
193 break;
194 case AF_INET6:
195 ZERO_STRUCT(ip6pkt);
196 ip6pkt.ip6.ip6_vfc = 0x60;
197 ip6pkt.ip6.ip6_plen = htons(20);
198 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
199 ip6pkt.ip6.ip6_hlim = 64;
200 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
201 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
203 ip6pkt.tcp.th_sport = src->ip6.sin6_port;
204 ip6pkt.tcp.th_dport = dest->ip6.sin6_port;
205 ip6pkt.tcp.th_seq = seq;
206 ip6pkt.tcp.th_ack = ack;
207 ip6pkt.tcp.th_flags = 0;
208 ip6pkt.tcp.th_flags |= TH_ACK;
209 if (rst) {
210 ip6pkt.tcp.th_flags |= TH_RST;
212 ip6pkt.tcp.th_off = sizeof(ip6pkt.tcp)/4;
213 /* this makes it easier to spot in a sniffer */
214 ip6pkt.tcp.th_win = htons(1234);
215 ip6pkt.tcp.th_sum = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
217 s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
218 if (s == -1) {
219 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
220 return -1;
223 /* sendto() don't like if the port is set and the socket is
224 in raw mode.
226 tmpdest = discard_const(dest);
227 tmpport = tmpdest->ip6.sin6_port;
229 tmpdest->ip6.sin6_port = 0;
230 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
231 (const struct sockaddr *)&dest->ip6,
232 sizeof(dest->ip6));
233 tmpdest->ip6.sin6_port = tmpport;
234 close(s);
236 if (ret != sizeof(ip6pkt)) {
237 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
238 return -1;
240 break;
242 default:
243 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
244 return -1;
247 return 0;
251 This function is used to open a raw socket to capture from
253 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
255 pcap_t *pt;
257 pt=pcap_open_live(iface, 100, 0, 0, NULL);
258 if (pt == NULL) {
259 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
260 return -1;
262 *((pcap_t **)private_data) = pt;
264 return pcap_fileno(pt);
267 /* This function is used to close the capture socket
269 int ctdb_sys_close_capture_socket(void *private_data)
271 pcap_t *pt = (pcap_t *)private_data;
272 pcap_close(pt);
273 return 0;
278 called when the raw socket becomes readable
280 int ctdb_sys_read_tcp_packet(int s, void *private_data,
281 ctdb_sock_addr *src, ctdb_sock_addr *dst,
282 uint32_t *ack_seq, uint32_t *seq)
284 int ret;
285 #define RCVPKTSIZE 100
286 char pkt[RCVPKTSIZE];
287 struct ether_header *eth;
288 struct ip *ip;
289 struct ip6_hdr *ip6;
290 struct tcphdr *tcp;
292 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
293 if (ret < sizeof(*eth)+sizeof(*ip)) {
294 return -1;
297 /* Ethernet */
298 eth = (struct ether_header *)pkt;
300 /* we want either IPv4 or IPv6 */
301 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
302 /* IP */
303 ip = (struct ip *)(eth+1);
305 /* We only want IPv4 packets */
306 if (ip->ip_v != 4) {
307 return -1;
309 /* Dont look at fragments */
310 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
311 return -1;
313 /* we only want TCP */
314 if (ip->ip_p != IPPROTO_TCP) {
315 return -1;
318 /* make sure its not a short packet */
319 if (offsetof(struct tcphdr, th_ack) + 4 +
320 (ip->ip_hl*4) + sizeof(*eth) > ret) {
321 return -1;
323 /* TCP */
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;
334 *seq = tcp->th_seq;
336 return 0;
337 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
338 /* IP6 */
339 ip6 = (struct ip6_hdr *)(eth+1);
341 /* we only want TCP */
342 if (ip6->ip6_nxt != IPPROTO_TCP) {
343 return -1;
346 /* TCP */
347 tcp = (struct tcphdr *)(ip6+1);
349 /* tell the caller which one we've found */
350 src->ip6.sin6_family = AF_INET6;
351 src->ip6.sin6_port = tcp->th_sport;
352 src->ip6.sin6_addr = ip6->ip6_src;
354 dst->ip6.sin6_family = AF_INET6;
355 dst->ip6.sin6_port = tcp->th_dport;
356 dst->ip6.sin6_addr = ip6->ip6_dst;
358 *ack_seq = tcp->th_ack;
359 *seq = tcp->th_seq;
361 return 0;
364 return -1;
367 bool ctdb_sys_check_iface_exists(const char *iface)
369 /* FIXME FreeBSD: Interface always considered present */
370 return true;
373 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
375 /* FIXME FreeBSD: get_peer_pid not implemented */
376 return 1;