2 ctdb system specific code to manage raw sockets on linux
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/>.
22 #include "system/network.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
25 #include "../include/ctdb_private.h"
26 #include "lib/events/events.h"
27 #include <netinet/if_ether.h>
28 #include <net/if_arp.h>
33 send gratuitous arp reply after we have taken over an ip address
35 saddr is the address we are trying to claim
36 iface is the interface name we will be using to claim the address
38 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface)
42 struct ether_header *eh;
44 struct ifreq if_hwaddr;
45 unsigned char buffer[64]; /*minimum eth frame size */
48 /* for now, we only handle AF_INET addresses */
49 if (saddr->sin_family != AF_INET) {
50 DEBUG(0,(__location__ " not an ipv4 address (family is %u)\n", saddr->sin_family));
54 s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
56 DEBUG(0,(__location__ " failed to open raw socket\n"));
60 /* get the mac address */
61 strcpy(if_hwaddr.ifr_name, iface);
62 ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
65 DEBUG(0,(__location__ " ioctl failed\n"));
68 if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
69 DEBUG(3,("Ignoring loopback arp request\n"));
73 if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
76 DEBUG(0,(__location__ " not an ethernet address family (0x%x)\n",
77 if_hwaddr.ifr_hwaddr.sa_family));
82 memset(buffer, 0 , 64);
83 eh = (struct ether_header *)buffer;
84 memset(eh->ether_dhost, 0xff, ETH_ALEN);
85 memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
86 eh->ether_type = htons(ETHERTYPE_ARP);
88 ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
89 ah->ar_hrd = htons(ARPHRD_ETHER);
90 ah->ar_pro = htons(ETH_P_IP);
91 ah->ar_hln = ETH_ALEN;
94 /* send a gratious arp */
95 ah->ar_op = htons(ARPOP_REQUEST);
97 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
99 memcpy(ptr, &saddr->sin_addr, 4);
101 memset(ptr, 0, ETH_ALEN);
103 memcpy(ptr, &saddr->sin_addr, 4);
106 strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
107 ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
110 DEBUG(0,(__location__ " failed sendto\n"));
114 /* send unsolicited arp reply broadcast */
115 ah->ar_op = htons(ARPOP_REPLY);
116 ptr = (char *)&ah[1];
117 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
119 memcpy(ptr, &saddr->sin_addr, 4);
121 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
123 memcpy(ptr, &saddr->sin_addr, 4);
126 strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
127 ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
129 DEBUG(0,(__location__ " failed sendto\n"));
139 uint16 checksum for n bytes
141 static uint32_t uint16_checksum(uint16_t *data, size_t n)
145 sum += (uint32_t)ntohs(*data);
150 sum += (uint32_t)ntohs(*(uint8_t *)data);
156 simple TCP checksum - assumes data is multiple of 2 bytes long
158 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
160 uint32_t sum = uint16_checksum(data, n);
162 sum += uint16_checksum((uint16_t *)&ip->saddr, sizeof(ip->saddr));
163 sum += uint16_checksum((uint16_t *)&ip->daddr, sizeof(ip->daddr));
164 sum += ip->protocol + n;
165 sum = (sum & 0xFFFF) + (sum >> 16);
166 sum = (sum & 0xFFFF) + (sum >> 16);
176 Send tcp segment from the specified IP/port to the specified
179 This is used to trigger the receiving host into sending its own ACK,
180 which should trigger early detection of TCP reset by the client
183 This can also be used to send RST segments (if rst is true) and also
184 if correct seq and ack numbers are provided.
186 int ctdb_sys_send_tcp(int s,
187 const struct sockaddr_in *dest,
188 const struct sockaddr_in *src,
189 uint32_t seq, uint32_t ack, int rst)
197 /* for now, we only handle AF_INET addresses */
198 if (src->sin_family != AF_INET || dest->sin_family != AF_INET) {
199 DEBUG(0,(__location__ " not an ipv4 address\n"));
205 pkt.ip.ihl = sizeof(pkt.ip)/4;
206 pkt.ip.tot_len = htons(sizeof(pkt));
208 pkt.ip.protocol = IPPROTO_TCP;
209 pkt.ip.saddr = src->sin_addr.s_addr;
210 pkt.ip.daddr = dest->sin_addr.s_addr;
213 pkt.tcp.source = src->sin_port;
214 pkt.tcp.dest = dest->sin_port;
216 pkt.tcp.ack_seq = ack;
221 pkt.tcp.doff = sizeof(pkt.tcp)/4;
222 pkt.tcp.window = htons(1234); /* this makes it easier to spot in a sniffer */
223 pkt.tcp.check = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
225 ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
226 if (ret != sizeof(pkt)) {
227 DEBUG(0,(__location__ " failed sendto (%s)\n", strerror(errno)));
236 see if we currently have an interface with the given IP
238 we try to bind to it, and if that fails then we don't have that IP
241 bool ctdb_sys_have_ip(const char *ip)
243 struct sockaddr_in sin;
248 inet_aton(ip, &sin.sin_addr);
249 sin.sin_family = AF_INET;
250 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
254 ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
260 This function is used to open a raw socket to capture from
262 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
266 /* Open a socket to capture all traffic */
267 s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
269 DEBUG(0,(__location__ " failed to open raw socket\n"));
274 set_close_on_exec(s);
280 This function is used to do any additional cleanup required when closing
282 Note that the socket itself is closed automatically in the caller.
284 int ctdb_sys_close_capture_socket(void *private_data)
290 This function is used to open a raw socket to send tickles from
292 int ctdb_sys_open_sending_socket(void)
297 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
299 DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
304 ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
306 DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
313 set_close_on_exec(s);
319 called when the raw socket becomes readable
321 int ctdb_sys_read_tcp_packet(int s, void *private_data,
322 struct sockaddr_in *src, struct sockaddr_in *dst,
323 uint32_t *ack_seq, uint32_t *seq)
326 #define RCVPKTSIZE 100
327 char pkt[RCVPKTSIZE];
328 struct ether_header *eth;
332 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
333 if (ret < sizeof(*eth)+sizeof(*ip)) {
338 eth = (struct ether_header *)pkt;
340 /* We only want IP packets */
341 if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
346 ip = (struct iphdr *)(eth+1);
348 /* We only want IPv4 packets */
349 if (ip->version != 4) {
352 /* Dont look at fragments */
353 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
356 /* we only want TCP */
357 if (ip->protocol != IPPROTO_TCP) {
361 /* make sure its not a short packet */
362 if (offsetof(struct tcphdr, ack_seq) + 4 +
363 (ip->ihl*4) + sizeof(*eth) > ret) {
368 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
370 /* tell the caller which one we've found */
371 src->sin_addr.s_addr = ip->saddr;
372 src->sin_port = tcp->source;
373 dst->sin_addr.s_addr = ip->daddr;
374 dst->sin_port = tcp->dest;
375 *ack_seq = tcp->ack_seq;