* interface. It will force traffic to be in 'ad-hoc' mode, use the
* proper MAC address of the WLAN interface and use a GNUnet-specific
* SSID (and a GNUnet-specific SNAP header). It only takes a single
- * argument, which is the name of the interface to use. Since it uses
- * RAW sockets, it must be installed SUID or run as 'root'. In order
- * to keep the security risk of the resulting SUID binary minimal, the
- * program ONLY opens the RAW socket with root privileges, then drops
- * them and only then starts to process command line arguments. The
- * code also does not link against any shared libraries (except libc)
- * and is strictly minimal (except for checking for errors). The
- * following list of people have reviewed this code and considered it
- * safe since the last modification (if you reviewed it, please have
- * your name added to the list):
+ * argument, which is the name of the WLAN interface to use. The
+ * program detects if the interface is not a WLAN interface and exits
+ * with an error in that case.
*
- * - Christian Grothoff (Mar 16th 2012)
+ * Once initialized, the program will first send a 'struct
+ * GNUNET_TRANSPORT_WLAN_HelperControlMessage' to 'stdout'. That
+ * message contains the MAC address of the WLAN interface. It will
+ * then read messages from the WLAN interface and send them together
+ * with performance information as 'struct
+ * GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage' messages to 'stdout'.
+ * Furthermore, it will read a stream of messages from 'stdin' that
+ * have the format from 'struct
+ * GNUNET_TRANSPORT_WLAN_RadiotapSendMessage'. Those messages will
+ * then be sent via the WLAN interface; however, the sender MAC
+ * address will be forced to be the correct address from our WLAN
+ * card. If 'stdin' closes, receiving from the WLAN interface will
+ * continue. If 'stdout' causes a SIGPIPE, the process dies from the
+ * signal. Errors cause an error message to be reported to 'stderr',
+ * in most cases the process also exits (with status code '1'). The
+ * program never terminates normally; it is safe to kill the
+ * process with SIGTERM or SIGKILL at any time.
+ *
+ * Since it uses RAW sockets, the binary must be installed SUID or run
+ * as 'root'. In order to keep the security risk of the resulting
+ * SUID binary minimal, the program ONLY opens the RAW socket with
+ * root privileges, then drops them and only then starts to process
+ * command line arguments. The code also does not link against any
+ * shared libraries (except libc) and is strictly minimal (except for
+ * checking for errors). The following list of people have reviewed
+ * this code and considered it safe since the last modification (if
+ * you reviewed it, please have your name added to the list):
+ *
+ * - Christian Grothoff (Apr 3rd 2012)
*/
/*-
/*
* parts taken from aircrack-ng, parts changend.
*/
-
-#define _GNU_SOURCE
+#include "gnunet_config.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include "gnunet_protocols.h"
#include "plugin_transport_wlan.h"
+/**
+ * Packet format type for the messages we receive from
+ * the kernel. This is for Ethernet 10Mbps format (no
+ * performance information included).
+ */
+#define ARPHRD_ETHER 1
+
+
/**
* Packet format type for the messages we receive from
* the kernel. This is for plain messages (with no
*/
#define ARPHRD_IEEE80211 801
+
/**
* Packet format type for the messages we receive from
* the kernel. This is for the PRISM format.
if (PRISM_STATUS_OK == pv.status)
{
ri->ri_noise = pv.data;
- got_noise = 1;
+ /* got_noise = 1; */
}
break;
case PRISM_DID_RATE:
if (PRISM_STATUS_OK == pv.status)
{
ri->ri_power = pv.data;
- got_signal = 1;
+ /* got_signal = 1; */
}
break;
}
case ARPHRD_IEEE80211:
n = 0; /* no header */
break;
+ case ARPHRD_ETHER:
+ {
+ if (sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) > caplen)
+ return 0; /* invalid */
+ memcpy (&buf[sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame)],
+ tmpbuf + sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame),
+ caplen - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) - 4 /* 4 byte FCS */);
+ return caplen - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) - 4;
+ }
default:
errno = ENOTSUP; /* unsupported format */
return -1;
IFNAMSIZ, dev->iface, strerror (errno));
return 1;
}
+ if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)) )
+ {
+ fprintf (stderr, "Error: interface `%.*s' is not using a supported hardware address family (got %d)\n",
+ IFNAMSIZ, dev->iface,
+ ifr.ifr_hwaddr.sa_family);
+ return 1;
+ }
/* lookup iw mode */
memset (&wrq, 0, sizeof (struct iwreq));
wrq.u.mode = IW_MODE_MONITOR;
}
- if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
- (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
- (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)) ||
- (wrq.u.mode != IW_MODE_MONITOR))
+ if ( (wrq.u.mode != IW_MODE_MONITOR) &&
+ (wrq.u.mode != IW_MODE_ADHOC) )
{
- fprintf (stderr, "Error: interface `%.*s' is not in monitor mode\n",
- IFNAMSIZ, dev->iface);
+ fprintf (stderr, "Error: interface `%.*s' is not in monitor or ad-hoc mode (got %d)\n",
+ IFNAMSIZ, dev->iface,
+ wrq.u.mode);
return 1;
}
memcpy (&dev->pl_mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE);
dev->arptype_in = ifr.ifr_hwaddr.sa_family;
- if ((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
+ if ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
(ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
(ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL))
{
mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
const struct HardwareInfos *dev)
{
+ static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;
+
+ if ( (0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
+ (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)) )
+ return 0; /* some drivers set no Macs, then assume it is all for us! */
+
if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
return 1; /* not a GNUnet ad-hoc package */
if ( (0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *wlanheader;
size_t sendsize;
struct RadiotapTransmissionHeader rtheader;
+ struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame etheader;
sendsize = ntohs (hdr->size);
if ( (sendsize <
sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
- (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type)) )
+ (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) )
{
fprintf (stderr, "Received malformed message\n");
exit (1);
sendsize -= (sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
if (MAXLINE < sendsize)
{
- fprintf (stderr, "Function stdin_send_hw: Packet too big for buffer\n");
+ fprintf (stderr, "Packet too big for buffer\n");
exit (1);
}
header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
- rtheader.header.it_version = 0;
- rtheader.header.it_pad = 0;
- rtheader.header.it_len = GNUNET_htole16 (sizeof (rtheader));
- rtheader.header.it_present = GNUNET_htole16 (IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK);
- rtheader.rate = header->rate;
- rtheader.pad1 = 0;
- rtheader.txflags = GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK | IEEE80211_RADIOTAP_F_TX_NOSEQ);
- memcpy (write_pout.buf, &rtheader, sizeof (rtheader));
- memcpy (&write_pout.buf[sizeof (rtheader)], &header->frame, sendsize);
- wlanheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf[sizeof (rtheader)];
-
- /* payload contains MAC address, but we don't trust it, so we'll
- * overwrite it with OUR MAC address to prevent mischief */
- mac_set (wlanheader, dev);
- write_pout.size = sendsize + sizeof (rtheader);
+ switch (dev->arptype_in)
+ {
+ case ARPHRD_IEEE80211_PRISM:
+ case ARPHRD_IEEE80211_FULL:
+ case ARPHRD_IEEE80211:
+ rtheader.header.it_version = 0;
+ rtheader.header.it_pad = 0;
+ rtheader.header.it_len = GNUNET_htole16 (sizeof (rtheader));
+ rtheader.header.it_present = GNUNET_htole16 (IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK);
+ rtheader.rate = header->rate;
+ rtheader.pad1 = 0;
+ rtheader.txflags = GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK | IEEE80211_RADIOTAP_F_TX_NOSEQ);
+ memcpy (write_pout.buf, &rtheader, sizeof (rtheader));
+ memcpy (&write_pout.buf[sizeof (rtheader)], &header->frame, sendsize);
+ wlanheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf[sizeof (rtheader)];
+
+ /* payload contains MAC address, but we don't trust it, so we'll
+ * overwrite it with OUR MAC address to prevent mischief */
+ mac_set (wlanheader, dev);
+ write_pout.size = sendsize + sizeof (rtheader);
+ break;
+ case ARPHRD_ETHER:
+ etheader.dst = header->frame.addr1;
+ /* etheader.src = header->frame.addr2; --- untrusted input */
+ etheader.src = dev->pl_mac;
+ etheader.type = htons (ETH_P_IP);
+ memcpy (write_pout.buf, ðeader, sizeof (etheader));
+ memcpy (&write_pout.buf[sizeof (etheader)], &header[1], sendsize - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
+ write_pout.size = sendsize - sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame) + sizeof (etheader);
+ break;
+ default:
+ fprintf (stderr,
+ "Unsupported ARPTYPE!\n");
+ break;
+ }
}
int stdin_open;
struct MessageStreamTokenizer *stdin_mst;
int raw_eno;
+ uid_t uid;
- memset (&dev, 0, sizeof (dev));
- dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
- raw_eno = errno; /* remember for later */
-
- /* drop privs */
- {
- uid_t uid = getuid ();
+ /* assert privs so we can modify the firewall rules! */
+ uid = getuid ();
#ifdef HAVE_SETRESUID
- if (0 != setresuid (uid, uid, uid))
- {
- fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
- if (-1 != dev.fd_raw)
- (void) close (dev.fd_raw);
- return 1;
- }
+ if (0 != setresuid (uid, 0, 0))
+ {
+ fprintf (stderr, "Failed to setresuid to root: %s\n", strerror (errno));
+ return 254;
+ }
#else
- if (0 != (setuid (uid) | seteuid (uid)))
- {
- fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
- if (-1 != dev.fd_raw)
- (void) close (dev.fd_raw);
- return 1;
- }
+ if (0 != seteuid (0))
+ {
+ fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno));
+ return 254;
}
#endif
+ /* make use of SGID capabilities on POSIX */
+ memset (&dev, 0, sizeof (dev));
+ dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
+ raw_eno = errno; /* remember for later */
+
/* now that we've dropped root rights, we can do error checking */
if (2 != argc)
{
return 1;
}
+ /* drop privs */
+ {
+ uid_t uid = getuid ();
+#ifdef HAVE_SETRESUID
+ if (0 != setresuid (uid, uid, uid))
+ {
+ fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
+ if (-1 != dev.fd_raw)
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+#else
+ if (0 != (setuid (uid) | seteuid (uid)))
+ {
+ fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
+ if (-1 != dev.fd_raw)
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+#endif
+ }
+
+
/* send MAC address of the WLAN interface to STDOUT first */
{
struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
+ sizeof (struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
- sizeof (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
rrm->header.size = htons (write_std.size);
- rrm->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+ rrm->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
}
}
}