Skip to content

Commit

Permalink
FC
Browse files Browse the repository at this point in the history
  • Loading branch information
DRTEK committed Apr 22, 2015
0 parents commit af446c6
Show file tree
Hide file tree
Showing 6 changed files with 1,610 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Makefile
CMakeCache.txt
CMakeFiles
*.cmake
install_manifest.txt
relayd
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 2.8)

PROJECT(relayd C)
ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3)

IF(APPLE)
INCLUDE_DIRECTORIES(/opt/local/include)
LINK_DIRECTORIES(/opt/local/lib)
ENDIF()

ADD_EXECUTABLE(relayd main.c dhcp.c route.c)
TARGET_LINK_LIBRARIES(relayd ubox)

SET(CMAKE_INSTALL_PREFIX /usr)

INSTALL(TARGETS relayd
RUNTIME DESTINATION sbin
)
176 changes: 176 additions & 0 deletions dhcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/

#define _GNU_SOURCE
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#include "relayd.h"

struct ip_packet {
struct ether_header eth;
struct iphdr iph;
} __packed;


enum {
DHCP_OPTION_ROUTER = 0x03,
DHCP_OPTION_ROUTES = 0x79,
DHCP_OPTION_END = 0xff,
};

struct dhcp_option {
uint8_t code;
uint8_t len;
uint8_t data[];
};

struct dhcp_header {
uint8_t op, htype, hlen, hops;
uint32_t xit;
uint16_t secs, flags;
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
unsigned char chaddr[16];
unsigned char sname[64];
unsigned char file[128];
uint32_t cookie;
uint8_t option_data[];
} __packed;

static uint16_t
chksum(uint16_t sum, const uint8_t *data, uint16_t len)
{
const uint8_t *last;
uint16_t t;

last = data + len - 1;

while(data < last) {
t = (data[0] << 8) + data[1];
sum += t;
if(sum < t)
sum++;
data += 2;
}

if(data == last) {
t = (data[0] << 8) + 0;
sum += t;
if(sum < t)
sum++;
}

return sum;
}

static void
parse_dhcp_options(struct relayd_host *host, struct dhcp_header *dhcp, int len)
{
uint8_t *end = (uint8_t *) dhcp + len;
struct dhcp_option *opt = (void *)dhcp->option_data;
static const uint8_t dest[4] = { 0, 0, 0, 0 };

while((uint8_t *) opt < end) {
if ((uint8_t *) opt + opt->len > end)
break;

opt = (void *) &opt->data[opt->len];
switch(opt->code) {
case DHCP_OPTION_ROUTER:
DPRINTF(2, "Found a DHCP router option, len=%d\n", opt->len);
if (!memcmp(opt->data, host->ipaddr, 4))
relayd_add_host_route(host, dest, 0);
else
relayd_add_pending_route(opt->data, dest, 0, 10000);
break;
case DHCP_OPTION_ROUTES:
DPRINTF(2, "Found a DHCP static routes option, len=%d\n", opt->len);
break;
case DHCP_OPTION_END:
opt = (void *) end;
continue;
default:
DPRINTF(3, "Skipping unknown DHCP option %02x\n", opt->code);
continue;
}

}
}

bool relayd_handle_dhcp_packet(struct relayd_interface *rif, void *data, int len, bool forward, bool parse)
{
struct ip_packet *pkt = data;
struct udphdr *udp;
struct dhcp_header *dhcp;
struct relayd_host *host;
int udplen;
uint16_t sum;

if (pkt->eth.ether_type != htons(ETH_P_IP))
return false;

if (pkt->iph.version != 4)
return false;

if (pkt->iph.protocol != IPPROTO_UDP)
return false;

udp = (void *) ((char *) &pkt->iph + (pkt->iph.ihl << 2));
dhcp = (void *) (udp + 1);

udplen = ntohs(udp->len);
if (udplen > len - ((char *) udp - (char *) data))
return false;

if (udp->dest != htons(67) && udp->source != htons(67))
return false;

if (dhcp->op != 1 && dhcp->op != 2)
return false;

if (!forward)
return true;

if (dhcp->op == 2) {
host = relayd_refresh_host(rif, pkt->eth.ether_shost, (void *) &pkt->iph.saddr);
if (host && parse)
parse_dhcp_options(host, dhcp, udplen - sizeof(struct udphdr));
}

DPRINTF(2, "%s: handling DHCP %s\n", rif->ifname, (dhcp->op == 1 ? "request" : "response"));

dhcp->flags |= htons(DHCP_FLAG_BROADCAST);

udp->check = 0;
sum = udplen + IPPROTO_UDP;
sum = chksum(sum, (void *) &pkt->iph.saddr, 8);
sum = chksum(sum, (void *) udp, udplen);
if (sum == 0)
sum = 0xffff;

udp->check = htons(~sum);

relayd_forward_bcast_packet(rif, data, len);

return true;
}


Loading

0 comments on commit af446c6

Please sign in to comment.