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.
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>
41 #include "common/logging.h"
42 #include "common/system.h"
43 #include "common/system_socket.h"
46 #define ETHERTYPE_IP6 0x86dd
50 calculate the tcp checksum for tcp over ipv6
52 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
58 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
59 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
62 phdr[1] = htonl(ip6->ip6_nxt);
63 sum += uint16_checksum((uint16_t *)phdr, 8);
65 sum += uint16_checksum(data, n);
67 sum = (sum & 0xFFFF) + (sum >> 16);
68 sum = (sum & 0xFFFF) + (sum >> 16);
78 send gratuitous arp reply after we have taken over an ip address
80 saddr is the address we are trying to claim
81 iface is the interface name we will be using to claim the address
83 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
85 /* FIXME GNU/Hurd: We don't do gratuitous arp yet */
91 simple TCP checksum - assumes data is multiple of 2 bytes long
93 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
95 uint32_t sum = uint16_checksum(data, n);
97 sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
99 sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
101 sum += ip->protocol + n;
102 sum = (sum & 0xFFFF) + (sum >> 16);
103 sum = (sum & 0xFFFF) + (sum >> 16);
113 Send tcp segment from the specified IP/port to the specified
116 This is used to trigger the receiving host into sending its own ACK,
117 which should trigger early detection of TCP reset by the client
120 This can also be used to send RST segments (if rst is true) and also
121 if correct seq and ack numbers are provided.
123 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
124 const ctdb_sock_addr *src,
125 uint32_t seq, uint32_t ack, int rst)
131 ctdb_sock_addr *tmpdest;
142 switch (src->ip.sin_family) {
145 ip4pkt.ip.version = 4;
146 ip4pkt.ip.ihl = sizeof(ip4pkt.ip)/4;
147 ip4pkt.ip.tot_len = htons(sizeof(ip4pkt));
149 ip4pkt.ip.protocol = IPPROTO_TCP;
150 ip4pkt.ip.saddr = src->ip.sin_addr.s_addr;
151 ip4pkt.ip.daddr = dest->ip.sin_addr.s_addr;
154 ip4pkt.tcp.source = src->ip.sin_port;
155 ip4pkt.tcp.dest = dest->ip.sin_port;
156 ip4pkt.tcp.seq = seq;
157 ip4pkt.tcp.ack_seq = ack;
162 ip4pkt.tcp.doff = sizeof(ip4pkt.tcp)/4;
163 /* this makes it easier to spot in a sniffer */
164 ip4pkt.tcp.window = htons(1234);
165 ip4pkt.tcp.check = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
167 /* open a raw socket to send this segment from */
168 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
170 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
175 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
177 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
183 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
184 &dest->ip, sizeof(dest->ip));
187 if (ret != sizeof(ip4pkt)) {
189 ("Failed sendto (%s)\n", strerror(saved_errno)));
195 ip6pkt.ip6.ip6_vfc = 0x60;
196 ip6pkt.ip6.ip6_plen = htons(20);
197 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
198 ip6pkt.ip6.ip6_hlim = 64;
199 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
200 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
202 ip6pkt.tcp.source = src->ip6.sin6_port;
203 ip6pkt.tcp.dest = dest->ip6.sin6_port;
204 ip6pkt.tcp.seq = seq;
205 ip6pkt.tcp.ack_seq = ack;
210 ip6pkt.tcp.doff = sizeof(ip6pkt.tcp)/4;
211 /* this makes it easier to spot in a sniffer */
212 ip6pkt.tcp.window = htons(1234);
213 ip6pkt.tcp.check = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
215 s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
217 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
221 /* sendto() don't like if the port is set and the socket is
224 tmpdest = discard_const(dest);
225 tmpport = tmpdest->ip6.sin6_port;
227 tmpdest->ip6.sin6_port = 0;
228 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
229 &dest->ip6, sizeof(dest->ip6));
231 tmpdest->ip6.sin6_port = tmpport;
234 if (ret != sizeof(ip6pkt)) {
236 ("Failed sendto (%s)\n", strerror(saved_errno)));
242 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
250 This function is used to open a raw socket to capture from
252 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
256 pt=pcap_open_live(iface, 100, 0, 0, NULL);
258 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
261 *((pcap_t **)private_data) = pt;
263 return pcap_fileno(pt);
266 /* This function is used to close the capture socket
268 int ctdb_sys_close_capture_socket(void *private_data)
270 pcap_t *pt = (pcap_t *)private_data;
277 called when the raw socket becomes readable
279 int ctdb_sys_read_tcp_packet(int s, void *private_data,
280 ctdb_sock_addr *src, ctdb_sock_addr *dst,
281 uint32_t *ack_seq, uint32_t *seq,
282 int *rst, uint16_t *window)
285 #define RCVPKTSIZE 100
286 char pkt[RCVPKTSIZE];
287 struct ether_header *eth;
292 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
293 if (ret < sizeof(*eth)+sizeof(*ip)) {
301 eth = (struct ether_header *)pkt;
303 /* we want either IPv4 or IPv6 */
304 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
306 ip = (struct iphdr *)(eth+1);
308 /* We only want IPv4 packets */
309 if (ip->version != 4) {
312 /* Dont look at fragments */
313 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
316 /* we only want TCP */
317 if (ip->protocol != IPPROTO_TCP) {
321 /* make sure its not a short packet */
322 if (offsetof(struct tcphdr, ack_seq) + 4 +
323 (ip->ihl*4) + sizeof(*eth) > ret) {
327 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
329 /* tell the caller which one we've found */
330 src->ip.sin_family = AF_INET;
331 src->ip.sin_addr.s_addr = ip->saddr;
332 src->ip.sin_port = tcp->source;
333 dst->ip.sin_family = AF_INET;
334 dst->ip.sin_addr.s_addr = ip->daddr;
335 dst->ip.sin_port = tcp->dest;
336 *ack_seq = tcp->ack_seq;
338 if (window != NULL) {
339 *window = tcp->window;
346 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
348 ip6 = (struct ip6_hdr *)(eth+1);
350 /* we only want TCP */
351 if (ip6->ip6_nxt != IPPROTO_TCP) {
356 tcp = (struct tcphdr *)(ip6+1);
358 /* tell the caller which one we've found */
359 src->ip6.sin6_family = AF_INET6;
360 src->ip6.sin6_port = tcp->source;
361 src->ip6.sin6_addr = ip6->ip6_src;
363 dst->ip6.sin6_family = AF_INET6;
364 dst->ip6.sin6_port = tcp->dest;
365 dst->ip6.sin6_addr = ip6->ip6_dst;
367 *ack_seq = tcp->ack_seq;
369 if (window != NULL) {
370 *window = tcp->window;
382 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
384 /* FIXME GNU/Hurd: get_peer_pid not implemented */