s4:dsdb/common: prepare dsdb_user_obj_set_defaults() for tombstone reanimation
[Samba.git] / ctdb / common / system_gnu.c
blob09c4ffef8e9558c20e547ffb242762850ad80cb4
1 /*
2 ctdb system specific code to manage raw sockets on linux
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
6 Copyright (C) Marc Dequènes (Duck) 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 This file is a copy of 'common/system_linux.c' adapted for Hurd needs,
23 and inspired by 'common/system_aix.c' for the pcap usage.
26 #include "replace.h"
27 #include "system/network.h"
28 #include "system/filesys.h"
29 #include "system/wait.h"
31 #include "lib/util/debug.h"
32 #include "lib/util/blocking.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 GNU/Hurd: 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 iphdr *ip)
94 uint32_t sum = uint16_checksum(data, n);
95 uint16_t sum2;
96 sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
97 sizeof(ip->saddr));
98 sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
99 sizeof(ip->daddr));
100 sum += ip->protocol + 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 iphdr 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.version = 4;
144 ip4pkt.ip.ihl = sizeof(ip4pkt.ip)/4;
145 ip4pkt.ip.tot_len = htons(sizeof(ip4pkt));
146 ip4pkt.ip.ttl = 255;
147 ip4pkt.ip.protocol = IPPROTO_TCP;
148 ip4pkt.ip.saddr = src->ip.sin_addr.s_addr;
149 ip4pkt.ip.daddr = dest->ip.sin_addr.s_addr;
150 ip4pkt.ip.check = 0;
152 ip4pkt.tcp.source = src->ip.sin_port;
153 ip4pkt.tcp.dest = dest->ip.sin_port;
154 ip4pkt.tcp.seq = seq;
155 ip4pkt.tcp.ack_seq = ack;
156 ip4pkt.tcp.ack = 1;
157 if (rst) {
158 ip4pkt.tcp.rst = 1;
160 ip4pkt.tcp.doff = sizeof(ip4pkt.tcp)/4;
161 /* this makes it easier to spot in a sniffer */
162 ip4pkt.tcp.window = htons(1234);
163 ip4pkt.tcp.check = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
165 /* open a raw socket to send this segment from */
166 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
167 if (s == -1) {
168 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
169 strerror(errno)));
170 return -1;
173 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
174 if (ret != 0) {
175 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
176 strerror(errno)));
177 close(s);
178 return -1;
181 set_blocking(s, false);
182 set_close_on_exec(s);
184 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, &dest->ip, sizeof(dest->ip));
185 close(s);
186 if (ret != sizeof(ip4pkt)) {
187 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
188 return -1;
190 break;
191 case AF_INET6:
192 ZERO_STRUCT(ip6pkt);
193 ip6pkt.ip6.ip6_vfc = 0x60;
194 ip6pkt.ip6.ip6_plen = htons(20);
195 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
196 ip6pkt.ip6.ip6_hlim = 64;
197 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
198 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
200 ip6pkt.tcp.source = src->ip6.sin6_port;
201 ip6pkt.tcp.dest = dest->ip6.sin6_port;
202 ip6pkt.tcp.seq = seq;
203 ip6pkt.tcp.ack_seq = ack;
204 ip6pkt.tcp.ack = 1;
205 if (rst) {
206 ip6pkt.tcp.rst = 1;
208 ip6pkt.tcp.doff = sizeof(ip6pkt.tcp)/4;
209 /* this makes it easier to spot in a sniffer */
210 ip6pkt.tcp.window = htons(1234);
211 ip6pkt.tcp.check = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
213 s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
214 if (s == -1) {
215 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
216 return -1;
219 /* sendto() don't like if the port is set and the socket is
220 in raw mode.
222 tmpdest = discard_const(dest);
223 tmpport = tmpdest->ip6.sin6_port;
225 tmpdest->ip6.sin6_port = 0;
226 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0, &dest->ip6, sizeof(dest->ip6));
227 tmpdest->ip6.sin6_port = tmpport;
228 close(s);
230 if (ret != sizeof(ip6pkt)) {
231 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
232 return -1;
234 break;
236 default:
237 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
238 return -1;
241 return 0;
245 This function is used to open a raw socket to capture from
247 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
249 pcap_t *pt;
251 pt=pcap_open_live(iface, 100, 0, 0, NULL);
252 if (pt == NULL) {
253 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
254 return -1;
256 *((pcap_t **)private_data) = pt;
258 return pcap_fileno(pt);
261 /* This function is used to close the capture socket
263 int ctdb_sys_close_capture_socket(void *private_data)
265 pcap_t *pt = (pcap_t *)private_data;
266 pcap_close(pt);
267 return 0;
272 called when the raw socket becomes readable
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)
279 int ret;
280 #define RCVPKTSIZE 100
281 char pkt[RCVPKTSIZE];
282 struct ether_header *eth;
283 struct iphdr *ip;
284 struct ip6_hdr *ip6;
285 struct tcphdr *tcp;
287 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
288 if (ret < sizeof(*eth)+sizeof(*ip)) {
289 return -1;
292 /* Ethernet */
293 eth = (struct ether_header *)pkt;
295 /* we want either IPv4 or IPv6 */
296 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
297 /* IP */
298 ip = (struct iphdr *)(eth+1);
300 /* We only want IPv4 packets */
301 if (ip->version != 4) {
302 return -1;
304 /* Dont look at fragments */
305 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
306 return -1;
308 /* we only want TCP */
309 if (ip->protocol != IPPROTO_TCP) {
310 return -1;
313 /* make sure its not a short packet */
314 if (offsetof(struct tcphdr, ack_seq) + 4 +
315 (ip->ihl*4) + sizeof(*eth) > ret) {
316 return -1;
318 /* TCP */
319 tcp = (struct tcphdr *)((ip->ihl*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->saddr;
324 src->ip.sin_port = tcp->source;
325 dst->ip.sin_family = AF_INET;
326 dst->ip.sin_addr.s_addr = ip->daddr;
327 dst->ip.sin_port = tcp->dest;
328 *ack_seq = tcp->ack_seq;
329 *seq = tcp->seq;
330 if (window != NULL) {
331 *window = tcp->window;
333 if (rst != NULL) {
334 *rst = tcp->rst;
337 return 0;
338 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
339 /* IP6 */
340 ip6 = (struct ip6_hdr *)(eth+1);
342 /* we only want TCP */
343 if (ip6->ip6_nxt != IPPROTO_TCP) {
344 return -1;
347 /* TCP */
348 tcp = (struct tcphdr *)(ip6+1);
350 /* tell the caller which one we've found */
351 src->ip6.sin6_family = AF_INET6;
352 src->ip6.sin6_port = tcp->source;
353 src->ip6.sin6_addr = ip6->ip6_src;
355 dst->ip6.sin6_family = AF_INET6;
356 dst->ip6.sin6_port = tcp->dest;
357 dst->ip6.sin6_addr = ip6->ip6_dst;
359 *ack_seq = tcp->ack_seq;
360 *seq = tcp->seq;
361 if (window != NULL) {
362 *window = tcp->window;
364 if (rst != NULL) {
365 *rst = tcp->rst;
368 return 0;
371 return -1;
374 bool ctdb_sys_check_iface_exists(const char *iface)
376 /* FIXME GNU/Hurd: Interface always considered present */
377 return true;
380 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
382 /* FIXME GNU/Hurd: get_peer_pid not implemented */
383 return 1;