s4:lib/socket: simplify iface_list_wildcard() and its callers
[Samba.git] / ctdb / common / system_gnu.c
blob2ab13996132d05480e9977d1a09baf60e25bf552
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 "includes.h"
27 #include "system/network.h"
28 #include "system/filesys.h"
29 #include "system/wait.h"
30 #include "../include/ctdb_private.h"
31 #include <net/ethernet.h>
32 #include <netinet/ip6.h>
33 #include <net/if_arp.h>
34 #include <pcap.h>
37 #ifndef ETHERTYPE_IP6
38 #define ETHERTYPE_IP6 0x86dd
39 #endif
42 calculate the tcp checksum for tcp over ipv6
44 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
46 uint32_t phdr[2];
47 uint32_t sum = 0;
48 uint16_t sum2;
50 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
51 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
53 phdr[0] = htonl(n);
54 phdr[1] = htonl(ip6->ip6_nxt);
55 sum += uint16_checksum((uint16_t *)phdr, 8);
57 sum += uint16_checksum(data, n);
59 sum = (sum & 0xFFFF) + (sum >> 16);
60 sum = (sum & 0xFFFF) + (sum >> 16);
61 sum2 = htons(sum);
62 sum2 = ~sum2;
63 if (sum2 == 0) {
64 return 0xFFFF;
66 return sum2;
70 send gratuitous arp reply after we have taken over an ip address
72 saddr is the address we are trying to claim
73 iface is the interface name we will be using to claim the address
75 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
77 /* FIXME GNU/Hurd: We dont do gratuitous arp yet */
78 return -1;
83 simple TCP checksum - assumes data is multiple of 2 bytes long
85 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
87 uint32_t sum = uint16_checksum(data, n);
88 uint16_t sum2;
89 sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
90 sizeof(ip->saddr));
91 sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
92 sizeof(ip->daddr));
93 sum += ip->protocol + n;
94 sum = (sum & 0xFFFF) + (sum >> 16);
95 sum = (sum & 0xFFFF) + (sum >> 16);
96 sum2 = htons(sum);
97 sum2 = ~sum2;
98 if (sum2 == 0) {
99 return 0xFFFF;
101 return sum2;
105 Send tcp segment from the specified IP/port to the specified
106 destination IP/port.
108 This is used to trigger the receiving host into sending its own ACK,
109 which should trigger early detection of TCP reset by the client
110 after IP takeover
112 This can also be used to send RST segments (if rst is true) and also
113 if correct seq and ack numbers are provided.
115 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
116 const ctdb_sock_addr *src,
117 uint32_t seq, uint32_t ack, int rst)
119 int s;
120 int ret;
121 uint32_t one = 1;
122 uint16_t tmpport;
123 ctdb_sock_addr *tmpdest;
124 struct {
125 struct iphdr ip;
126 struct tcphdr tcp;
127 } ip4pkt;
128 struct {
129 struct ip6_hdr ip6;
130 struct tcphdr tcp;
131 } ip6pkt;
133 switch (src->ip.sin_family) {
134 case AF_INET:
135 ZERO_STRUCT(ip4pkt);
136 ip4pkt.ip.version = 4;
137 ip4pkt.ip.ihl = sizeof(ip4pkt.ip)/4;
138 ip4pkt.ip.tot_len = htons(sizeof(ip4pkt));
139 ip4pkt.ip.ttl = 255;
140 ip4pkt.ip.protocol = IPPROTO_TCP;
141 ip4pkt.ip.saddr = src->ip.sin_addr.s_addr;
142 ip4pkt.ip.daddr = dest->ip.sin_addr.s_addr;
143 ip4pkt.ip.check = 0;
145 ip4pkt.tcp.source = src->ip.sin_port;
146 ip4pkt.tcp.dest = dest->ip.sin_port;
147 ip4pkt.tcp.seq = seq;
148 ip4pkt.tcp.ack_seq = ack;
149 ip4pkt.tcp.ack = 1;
150 if (rst) {
151 ip4pkt.tcp.rst = 1;
153 ip4pkt.tcp.doff = sizeof(ip4pkt.tcp)/4;
154 /* this makes it easier to spot in a sniffer */
155 ip4pkt.tcp.window = htons(1234);
156 ip4pkt.tcp.check = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
158 /* open a raw socket to send this segment from */
159 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
160 if (s == -1) {
161 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
162 strerror(errno)));
163 return -1;
166 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
167 if (ret != 0) {
168 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
169 strerror(errno)));
170 close(s);
171 return -1;
174 set_nonblocking(s);
175 set_close_on_exec(s);
177 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, &dest->ip, sizeof(dest->ip));
178 close(s);
179 if (ret != sizeof(ip4pkt)) {
180 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
181 return -1;
183 break;
184 case AF_INET6:
185 ZERO_STRUCT(ip6pkt);
186 ip6pkt.ip6.ip6_vfc = 0x60;
187 ip6pkt.ip6.ip6_plen = htons(20);
188 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
189 ip6pkt.ip6.ip6_hlim = 64;
190 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
191 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
193 ip6pkt.tcp.source = src->ip6.sin6_port;
194 ip6pkt.tcp.dest = dest->ip6.sin6_port;
195 ip6pkt.tcp.seq = seq;
196 ip6pkt.tcp.ack_seq = ack;
197 ip6pkt.tcp.ack = 1;
198 if (rst) {
199 ip6pkt.tcp.rst = 1;
201 ip6pkt.tcp.doff = sizeof(ip6pkt.tcp)/4;
202 /* this makes it easier to spot in a sniffer */
203 ip6pkt.tcp.window = htons(1234);
204 ip6pkt.tcp.check = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
206 s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
207 if (s == -1) {
208 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
209 return -1;
212 /* sendto() dont like if the port is set and the socket is
213 in raw mode.
215 tmpdest = discard_const(dest);
216 tmpport = tmpdest->ip6.sin6_port;
218 tmpdest->ip6.sin6_port = 0;
219 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0, &dest->ip6, sizeof(dest->ip6));
220 tmpdest->ip6.sin6_port = tmpport;
221 close(s);
223 if (ret != sizeof(ip6pkt)) {
224 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
225 return -1;
227 break;
229 default:
230 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
231 return -1;
234 return 0;
238 This function is used to open a raw socket to capture from
240 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
242 pcap_t *pt;
244 pt=pcap_open_live(iface, 100, 0, 0, NULL);
245 if (pt == NULL) {
246 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
247 return -1;
249 *((pcap_t **)private_data) = pt;
251 return pcap_fileno(pt);
254 /* This function is used to close the capture socket
256 int ctdb_sys_close_capture_socket(void *private_data)
258 pcap_t *pt = (pcap_t *)private_data;
259 pcap_close(pt);
260 return 0;
265 called when the raw socket becomes readable
267 int ctdb_sys_read_tcp_packet(int s, void *private_data,
268 ctdb_sock_addr *src, ctdb_sock_addr *dst,
269 uint32_t *ack_seq, uint32_t *seq)
271 int ret;
272 #define RCVPKTSIZE 100
273 char pkt[RCVPKTSIZE];
274 struct ether_header *eth;
275 struct iphdr *ip;
276 struct ip6_hdr *ip6;
277 struct tcphdr *tcp;
279 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
280 if (ret < sizeof(*eth)+sizeof(*ip)) {
281 return -1;
284 /* Ethernet */
285 eth = (struct ether_header *)pkt;
287 /* we want either IPv4 or IPv6 */
288 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
289 /* IP */
290 ip = (struct iphdr *)(eth+1);
292 /* We only want IPv4 packets */
293 if (ip->version != 4) {
294 return -1;
296 /* Dont look at fragments */
297 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
298 return -1;
300 /* we only want TCP */
301 if (ip->protocol != IPPROTO_TCP) {
302 return -1;
305 /* make sure its not a short packet */
306 if (offsetof(struct tcphdr, ack_seq) + 4 +
307 (ip->ihl*4) + sizeof(*eth) > ret) {
308 return -1;
310 /* TCP */
311 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
313 /* tell the caller which one we've found */
314 src->ip.sin_family = AF_INET;
315 src->ip.sin_addr.s_addr = ip->saddr;
316 src->ip.sin_port = tcp->source;
317 dst->ip.sin_family = AF_INET;
318 dst->ip.sin_addr.s_addr = ip->daddr;
319 dst->ip.sin_port = tcp->dest;
320 *ack_seq = tcp->ack_seq;
321 *seq = tcp->seq;
323 return 0;
324 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
325 /* IP6 */
326 ip6 = (struct ip6_hdr *)(eth+1);
328 /* we only want TCP */
329 if (ip6->ip6_nxt != IPPROTO_TCP) {
330 return -1;
333 /* TCP */
334 tcp = (struct tcphdr *)(ip6+1);
336 /* tell the caller which one we've found */
337 src->ip6.sin6_family = AF_INET6;
338 src->ip6.sin6_port = tcp->source;
339 src->ip6.sin6_addr = ip6->ip6_src;
341 dst->ip6.sin6_family = AF_INET6;
342 dst->ip6.sin6_port = tcp->dest;
343 dst->ip6.sin6_addr = ip6->ip6_dst;
345 *ack_seq = tcp->ack_seq;
346 *seq = tcp->seq;
348 return 0;
351 return -1;
354 bool ctdb_sys_check_iface_exists(const char *iface)
356 /* FIXME GNU/Hurd: Interface always considered present */
357 return true;
360 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
362 /* FIXME GNU/Hurd: get_peer_pid not implemented */
363 return 1;
366 char *ctdb_get_process_name(pid_t pid)
368 /* FIXME GNU/Hurd: get_process_name not implemented */
369 return NULL;
372 int ctdb_set_process_name(const char *name)
374 /* FIXME GNU/Hurd: set_process_name not implemented */
375 return -ENOSYS;
378 bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
380 /* FIXME GNU/Hurd: get_lock_info not implemented */
381 return false;
384 bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
386 /* FIXME GNU/Hurd: get_blocker_pid not implemented */
387 return false;