Compare commits

..

No commits in common. "841ea0cec24cf761ceea3c16c116172ffa1c3814" and "395bb5c76422c8e8423730b2d17498aa330ce85d" have entirely different histories.

11 changed files with 216 additions and 504 deletions

View File

@ -19,10 +19,9 @@ OBJS = \
udp4.o \ udp4.o \
eth.o \ eth.o \
rtnetlink.o \ rtnetlink.o \
interface.o \ interface.o
sock.o
all: client server test2 all: client test2
%.o: %.cpp %.o: %.cpp
$(CXX) $(CFLAGS) $(CXXFLAGS) $(FREETYPE_CFLAGS) -c $< -o $@ $(CXX) $(CFLAGS) $(CXXFLAGS) $(FREETYPE_CFLAGS) -c $< -o $@

View File

@ -7,7 +7,13 @@
#include <fcntl.h> #include <fcntl.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_packet.h> #include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <linux/filter.h>
#include "ip4.h" #include "ip4.h"
#include "udp4.h" #include "udp4.h"
@ -15,74 +21,191 @@
#include "eth.h" #include "eth.h"
#include "packet.h" #include "packet.h"
#include "interface.h" #include "interface.h"
#include "sock.h"
void print_message(packet::packet const& p, dhcp4::options const& options) void interface_send(int sock,
int interface_index,
void * buf,
int length,
uint8_t const * eth_destination_address)
{ {
printf("dhcp4 op: %d\n", p.dhcp4->op); struct sockaddr_ll socket_address;
printf("dhcp4 yiaddr: %s\n", ip4::tostr(p.dhcp4->yiaddr)); socket_address.sll_ifindex = interface_index;
socket_address.sll_halen = ETH_ALEN;
memcpy(socket_address.sll_addr, eth_destination_address, 6);
int flags = 0;
int sret = sendto(sock, buf, length, flags,
(struct sockaddr *)&socket_address, sizeof(struct sockaddr_ll));
if (sret < 0) {
perror("sendto");
exit(EXIT_FAILURE);
}
}
printf("message type: %s\n", dhcp4::message_type_tostr(options.message_type)); void attach_dhcp_filter(int sock)
printf("subnet mask: %s\n", ip4::tostr(options.subnet_mask)); {
printf("router: %s\n", ip4::tostr(options.router)); struct sock_filter filter[] = {
printf("domain name server: %s\n", ip4::tostr(options.domain_name_server)); { 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 6, 0x00000011 },
{ 0x28, 0, 0, 0x00000014 },
{ 0x45, 4, 0, 0x00001fff },
{ 0xb1, 0, 0, 0x0000000e },
{ 0x48, 0, 0, 0x00000010 },
{ 0x15, 0, 1, 0x00000044 },
{ 0x06, 0, 0, 0x00040000 },
{ 0x06, 0, 0, 0000000000 },
};
struct sock_fprog fprog = {
.len = sizeof(filter) / sizeof(filter[0]),
.filter = filter,
};
int ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, (sizeof (fprog)));
if (ret < 0) {
perror("setsockopt(SO_ATTACH_FILTER)");
exit(EXIT_FAILURE);
}
} }
int main() int main()
{ {
srand(time(NULL)); srand(time(NULL));
uint32_t dhcp_transaction_id = rand();
int sock = sock::create(68); uint8_t buf[16384];
//////////////////////////////////////////////////////////////////////
// socket
//////////////////////////////////////////////////////////////////////
int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
if (s < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
{
int enable = 1;
int ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &enable, (sizeof (int)));
if (ret < 0) {
perror("setsockopt(SO_BROADCAST)");
exit(EXIT_FAILURE);
}
}
//////////////////////////////////////////////////////////////////////
// interface index
//////////////////////////////////////////////////////////////////////
char const * interface_name = "wlp174s0"; char const * interface_name = "wlp174s0";
int ifa_index = sock::interface_index(sock, interface_name);
sock::bind_interface(sock, ifa_index);
uint8_t eth_source_address[6]; struct ifreq if_index;
sock::interface_address(sock, interface_name, eth_source_address); memset(&if_index, 0, (sizeof (struct ifreq)));
strncpy(if_index.ifr_name, interface_name, IFNAMSIZ - 1);
int iret = ioctl(s, SIOCGIFINDEX, &if_index);
if (iret < 0) {
perror("ioctl(SIOCGIFINDEX)");
exit(EXIT_FAILURE);
}
int ifa_index = if_index.ifr_ifindex;
printf("interface index %d\n", ifa_index);
//////////////////////////////////////////////////////////////////////
// interface address
//////////////////////////////////////////////////////////////////////
struct ifreq if_hwaddr;
memset(&if_hwaddr, 0, sizeof(struct ifreq));
strncpy(if_hwaddr.ifr_name, interface_name, IFNAMSIZ - 1);
int hret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
if (hret < 0) {
perror("ioctl(SIOCGIFHWADDR)");
exit(EXIT_FAILURE);
}
printf("hardware address %02x:%02x:%02x:%02x:%02x:%02x\n",
(uint8_t)if_hwaddr.ifr_hwaddr.sa_data[0], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[1],
(uint8_t)if_hwaddr.ifr_hwaddr.sa_data[2], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[3],
(uint8_t)if_hwaddr.ifr_hwaddr.sa_data[4], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[5]);
//////////////////////////////////////////////////////////////////////
// bind
//////////////////////////////////////////////////////////////////////
struct sockaddr_ll bind_addr_ll = {
.sll_family = AF_PACKET,
.sll_protocol = htons(ETH_P_IP),
.sll_ifindex = ifa_index,
};
int bret_ll = bind(s, (struct sockaddr *)&bind_addr_ll, (sizeof (struct sockaddr_ll)));
if (bret_ll < 0) {
perror("bind ll");
exit(EXIT_FAILURE);
}
attach_dhcp_filter(s);
//////////////////////////////////////////////////////////////////////
// fake socket
//////////////////////////////////////////////////////////////////////
int sf;
{
sf = socket(AF_INET, SOCK_DGRAM, 0);
if (sf < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// this has the effect of inhibiting linux's generation of icmp
// "destination unreachable" packets
struct sockaddr_in bind_addr_in = {
.sin_family = AF_INET,
.sin_port = htons(68),
.sin_addr = { .s_addr = INADDR_ANY },
};
int bret_in = bind(sf, (struct sockaddr *)&bind_addr_in, (sizeof (struct sockaddr_in)));
if (bret_in < 0) {
perror("bind in");
exit(EXIT_FAILURE);
}
}
//////////////////////////////////////////////////////////////////////
// dhcp send discover
//////////////////////////////////////////////////////////////////////
uint32_t dhcp_transaction_id = rand();
uint8_t eth_source_address[6] = {};
memcpy(eth_source_address, if_hwaddr.ifr_hwaddr.sa_data, 6);
uint8_t eth_destination_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; uint8_t eth_destination_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint32_t ip4_source_address = 0x00000000; uint32_t ip4_source_address = 0x00000000;
uint32_t ip4_destination_address = 0xffffffff; uint32_t ip4_destination_address = 0xffffffff;
packet::packet p{}; int length = packet::make(buf,
dhcp4::options options{}; eth_source_address,
static uint8_t recvbuf[65536]; eth_destination_address,
static uint8_t sendbuf[16384]; ip4_source_address,
ip4_destination_address,
dhcp_transaction_id,
dhcp4::message_type::dhcpdiscover,
0);
////////////////////////////////////////////////////////////////////// interface_send(s, ifa_index, buf, length, eth_destination_address);
// dhcp send discover
//////////////////////////////////////////////////////////////////////
{
dhcp4::message_parameters params = {
};
int length = packet::make(sendbuf,
dhcp4::op::bootrequest,
eth_source_address,
eth_destination_address,
eth_source_address, // eth_client_address
ip4_source_address,
ip4_destination_address,
68, // udp4_source_port
67, // udp4_destination_port
dhcp_transaction_id,
dhcp4::message_type::dhcpdiscover,
&params);
sock::send(sock, ifa_index, sendbuf, length, eth_destination_address);
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// dhcp recv offer // dhcp recv offer
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
packet::packet p{};
dhcp4::options options{};
uint8_t recvbuf[65536];
{ {
struct sockaddr_ll recv_address; struct sockaddr_ll recv_address;
int flags = 0; int flags = 0;
socklen_t socklen = (sizeof (struct sockaddr_ll)); socklen_t socklen = (sizeof (struct sockaddr_ll));
ssize_t rret = recvfrom(sock, recvbuf, (sizeof (recvbuf)), flags, ssize_t rret = recvfrom(s, recvbuf, (sizeof (recvbuf)), flags,
(struct sockaddr *)&recv_address, &socklen); (struct sockaddr *)&recv_address, &socklen);
if (rret < 0) { if (rret < 0) {
perror("recvfrom"); perror("recvfrom");
@ -90,9 +213,16 @@ int main()
} }
packet::parse(recvbuf, rret, &p); packet::parse(recvbuf, rret, &p);
printf("dhcp4 op: %d\n", p.dhcp4->op);
printf("dhcp4 yiaddr: %s\n", ip4::tostr(p.dhcp4->yiaddr));
int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options))); int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options)));
dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options); dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options);
print_message(p, options); printf("message type: %s\n", dhcp4::message_type_tostr(options.message_type));
printf("subnet mask: %s\n", ip4::tostr(options.subnet_mask));
printf("router: %s\n", ip4::tostr(options.router));
printf("domain name server: %s\n", ip4::tostr(options.domain_name_server));
assert(p.dhcp4->op == dhcp4::op::bootreply); assert(p.dhcp4->op == dhcp4::op::bootreply);
assert(options.message_type == dhcp4::message_type::dhcpoffer); assert(options.message_type == dhcp4::message_type::dhcpoffer);
@ -103,24 +233,16 @@ int main()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
{ {
dhcp4::message_parameters params = { int length = packet::make(buf,
.requested_ip_address = p.dhcp4->yiaddr,
};
int length = packet::make(sendbuf,
dhcp4::op::bootrequest,
eth_source_address, eth_source_address,
eth_destination_address, eth_destination_address,
eth_source_address, // eth_client_address
ip4_source_address, ip4_source_address,
ip4_destination_address, ip4_destination_address,
68, // udp4_source_port
67, // udp4_destination_port
dhcp_transaction_id, dhcp_transaction_id,
dhcp4::message_type::dhcprequest, dhcp4::message_type::dhcprequest,
&params); p.dhcp4->yiaddr);
sock::send(sock, ifa_index, sendbuf, length, eth_destination_address); interface_send(s, ifa_index, buf, length, eth_destination_address);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -131,7 +253,7 @@ int main()
struct sockaddr_ll recv_address; struct sockaddr_ll recv_address;
int flags = 0; int flags = 0;
socklen_t socklen = (sizeof (struct sockaddr_ll)); socklen_t socklen = (sizeof (struct sockaddr_ll));
ssize_t rret = recvfrom(sock, recvbuf, (sizeof (recvbuf)), flags, ssize_t rret = recvfrom(s, recvbuf, (sizeof (recvbuf)), flags,
(struct sockaddr *)&recv_address, &socklen); (struct sockaddr *)&recv_address, &socklen);
if (rret < 0) { if (rret < 0) {
perror("recvfrom"); perror("recvfrom");
@ -139,9 +261,16 @@ int main()
} }
packet::parse(recvbuf, rret, &p); packet::parse(recvbuf, rret, &p);
printf("dhcp4 op: %d\n", p.dhcp4->op);
printf("dhcp4 yiaddr: %s\n", ip4::tostr(p.dhcp4->yiaddr));
int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options))); int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options)));
dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options); dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options);
print_message(p, options); printf("message type: %s\n", dhcp4::message_type_tostr(options.message_type));
printf("subnet mask: %s\n", ip4::tostr(options.subnet_mask));
printf("router: %s\n", ip4::tostr(options.router));
printf("domain name server: %s\n", ip4::tostr(options.domain_name_server));
assert(p.dhcp4->op == dhcp4::op::bootreply); assert(p.dhcp4->op == dhcp4::op::bootreply);
assert(options.message_type == dhcp4::message_type::dhcpack); assert(options.message_type == dhcp4::message_type::dhcpack);
@ -189,6 +318,7 @@ int main()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
close(dfd); close(dfd);
close(sock); close(s);
close(sf);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View File

@ -8,36 +8,12 @@
namespace dhcp4 { namespace dhcp4 {
int add_parameter_request_list(message * msg, int index)
{
uint8_t * opt = &msg->options[index];
int length = 3;
index += 2 + length;
opt[0] = option::parameter_request_list;
opt[1] = length;
opt[2] = option::subnet_mask;
opt[3] = option::router;
opt[4] = option::domain_name_server;
return index;
}
int add_uint32(message * msg, int index, uint8_t option, uint32_t value)
{
uint8_t * opt = &msg->options[index];
int length = 4;
index += 2 + length;
opt[0] = option;
opt[1] = length;
memcpy(&opt[2], &value, 4);
return index;
}
int make_message(void * buf, int make_message(void * buf,
uint32_t bootp_message_type, uint32_t bootp_message_type,
uint32_t transaction_id, uint32_t transaction_id,
uint8_t const * chaddr, uint8_t const * chaddr,
uint32_t dhcp_message_type, uint32_t dhcp_message_type,
message_parameters const * params) uint32_t requested_ip_address)
{ {
memset(buf, 0, (sizeof (message))); memset(buf, 0, (sizeof (message)));
message * msg = reinterpret_cast<message *>(buf); message * msg = reinterpret_cast<message *>(buf);
@ -46,10 +22,6 @@ namespace dhcp4 {
msg->htype = htype::ethernet; msg->htype = htype::ethernet;
msg->hlen = 6; msg->hlen = 6;
msg->xid = htonl(transaction_id); msg->xid = htonl(transaction_id);
msg->yiaddr = params->your_ip_address;
msg->siaddr = params->next_server_ip_address;
memcpy(msg->chaddr, chaddr, 6); memcpy(msg->chaddr, chaddr, 6);
int index = 0; int index = 0;
@ -67,31 +39,24 @@ namespace dhcp4 {
message_type[1] = 1; // length message_type[1] = 1; // length
message_type[2] = dhcp_message_type; message_type[2] = dhcp_message_type;
if (dhcp_message_type == message_type::dhcpdiscover || {
dhcp_message_type == message_type::dhcprequest) { uint8_t * prl = &msg->options[index];
index = add_parameter_request_list(msg, index); int length = 3;
index += 2 + length;
prl[0] = option::parameter_request_list;
prl[1] = length;
prl[2] = option::subnet_mask;
prl[3] = option::router;
prl[4] = option::domain_name_server;
} }
if (params->subnet_mask != 0) { if (requested_ip_address != 0) {
index = add_uint32(msg, index, option::subnet_mask, params->subnet_mask); uint8_t * addr = &msg->options[index];
} int length = 4;
index += 2 + length;
if (params->server_identifier != 0) { addr[0] = option::requested_ip_address;
index = add_uint32(msg, index, option::server_identifier, params->server_identifier); addr[1] = length;
memcpy(&addr[2], &requested_ip_address, 4);
index = add_uint32(msg, index, option::ip_address_lease_time, htonl(86400));
}
if (params->router != 0) {
index = add_uint32(msg, index, option::router, params->router);
}
if (params->domain_name_server != 0) {
index = add_uint32(msg, index, option::domain_name_server, params->domain_name_server);
}
if (params->requested_ip_address != 0) {
index = add_uint32(msg, index, option::requested_ip_address, params->requested_ip_address);
} }
uint8_t * end = &msg->options[index]; uint8_t * end = &msg->options[index];
@ -125,11 +90,10 @@ namespace dhcp4 {
int index = 4; int index = 4;
while (index + 2 <= options_length) { while (index + 2 <= options_length) {
int option = options[index + 0]; int option = options[index + 0];
if (option == option::end) {
break;
}
int option_length = options[index + 1]; int option_length = options[index + 1];
//printf("option %d length %d\n", option, option_length);
switch (option) { switch (option) {
case option::message_type: case option::message_type:
o->message_type = options[index + 2]; o->message_type = options[index + 2];
@ -143,19 +107,12 @@ namespace dhcp4 {
case option::domain_name_server: case option::domain_name_server:
o->domain_name_server = *reinterpret_cast<uint32_t const *>(&options[index + 2]); o->domain_name_server = *reinterpret_cast<uint32_t const *>(&options[index + 2]);
break; break;
case option::requested_ip_address:
o->requested_ip_address = *reinterpret_cast<uint32_t const *>(&options[index + 2]);
break;
default: default:
break; break;
} }
index += 2 + option_length; index += 2 + option_length;
} }
assert(options[index] == 255);
assert(options[index] == option::end);
for (index = index + 1; index < options_length; index++) {
assert(options[index] == 0);
}
} }
} }

14
dhcp4.h
View File

@ -28,7 +28,6 @@ namespace dhcp4 {
uint32_t subnet_mask; // 1 uint32_t subnet_mask; // 1
uint32_t router; // 3 uint32_t router; // 3
uint32_t domain_name_server; // 6 uint32_t domain_name_server; // 6
uint32_t requested_ip_address; // 50
}; };
struct op { struct op {
@ -60,7 +59,6 @@ namespace dhcp4 {
parameter_request_list = 55, parameter_request_list = 55,
maximum_message_size = 57, maximum_message_size = 57,
client_identifier = 61, client_identifier = 61,
end = 255,
}; };
}; };
@ -77,22 +75,12 @@ namespace dhcp4 {
}; };
}; };
struct message_parameters {
uint32_t your_ip_address;
uint32_t next_server_ip_address;
uint32_t server_identifier;
uint32_t subnet_mask;
uint32_t router;
uint32_t domain_name_server;
uint32_t requested_ip_address;
};
int make_message(void * buf, int make_message(void * buf,
uint32_t bootp_message_type, uint32_t bootp_message_type,
uint32_t transaction_id, uint32_t transaction_id,
uint8_t const * chaddr, uint8_t const * chaddr,
uint32_t dhcp_message_type, uint32_t dhcp_message_type,
message_parameters const * params); uint32_t requested_ip_address);
char const * message_type_tostr(int message_type); char const * message_type_tostr(int message_type);

View File

@ -1,4 +1,3 @@
#include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
@ -15,14 +14,6 @@ namespace ip4 {
return inet_ntop(AF_INET, reinterpret_cast<void const *>(&a), tmp, 16); return inet_ntop(AF_INET, reinterpret_cast<void const *>(&a), tmp, 16);
} }
uint32_t fromstr(char const * s)
{
uint32_t value;
int ret = inet_pton(AF_INET, s, reinterpret_cast<void *>(&value));
assert(ret == 1);
return value;
}
uint32_t checksum_partial(uint32_t sum, void const * src, int length) uint32_t checksum_partial(uint32_t sum, void const * src, int length)
{ {
uint8_t const * addr = reinterpret_cast<uint8_t const *>(src); uint8_t const * addr = reinterpret_cast<uint8_t const *>(src);

1
ip4.h
View File

@ -20,7 +20,6 @@ namespace ip4 {
static_assert((sizeof (header)) == 20); static_assert((sizeof (header)) == 20);
char const * tostr(uint32_t a); char const * tostr(uint32_t a);
uint32_t fromstr(char const * s);
uint32_t checksum_partial(uint32_t sum, void const * src, int length); uint32_t checksum_partial(uint32_t sum, void const * src, int length);
uint32_t checksum_finish(uint32_t sum); uint32_t checksum_finish(uint32_t sum);

View File

@ -62,28 +62,24 @@ namespace packet {
} }
int make(uint8_t * buf, int make(uint8_t * buf,
uint8_t const op,
uint8_t const * eth_source_address, uint8_t const * eth_source_address,
uint8_t const * eth_destination_address, uint8_t const * eth_destination_address,
uint8_t const * eth_client_address,
uint32_t const ip4_source_address, uint32_t const ip4_source_address,
uint32_t const ip4_destination_address, uint32_t const ip4_destination_address,
uint16_t const udp4_source_port,
uint16_t const udp4_destination_port,
uint32_t const dhcp_transaction_id, uint32_t const dhcp_transaction_id,
uint32_t const dhcp_message_type, uint32_t const dhcp_message_type,
dhcp4::message_parameters const * params) uint32_t const requested_ip_address)
{ {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// dhcp4 // dhcp4
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
int dhcp4_length = dhcp4::make_message(reinterpret_cast<void *>(&buf[dhcp4_offset]), int dhcp4_length = dhcp4::make_message(reinterpret_cast<void *>(&buf[dhcp4_offset]),
op, dhcp4::op::bootrequest,
dhcp_transaction_id, dhcp_transaction_id,
eth_client_address, eth_source_address,
dhcp_message_type, dhcp_message_type,
params); requested_ip_address);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// eth // eth
@ -111,8 +107,8 @@ namespace packet {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
udp4::make_header(reinterpret_cast<void *>(&buf[udp4_offset]), udp4::make_header(reinterpret_cast<void *>(&buf[udp4_offset]),
htons(udp4_source_port), htons(68),
htons(udp4_destination_port), htons(67),
ip4_source_address, ip4_source_address,
ip4_destination_address, ip4_destination_address,
&buf[dhcp4_offset], &buf[dhcp4_offset],

View File

@ -21,15 +21,11 @@ namespace packet {
const int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)) + (sizeof (udp4::header)); const int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)) + (sizeof (udp4::header));
int make(uint8_t * buf, int make(uint8_t * buf,
uint8_t op,
uint8_t const * eth_source_address, uint8_t const * eth_source_address,
uint8_t const * eth_destination_address, uint8_t const * eth_destination_address,
uint8_t const * eth_client_address,
uint32_t const ip4_source_address, uint32_t const ip4_source_address,
uint32_t const ip4_destination_address, uint32_t const ip4_destination_address,
uint16_t const udp4_source_port,
uint16_t const udp4_destination_port,
uint32_t const dhcp_transaction_id, uint32_t const dhcp_transaction_id,
uint32_t const dhcp_message_type, uint32_t const dhcp_message_type,
dhcp4::message_parameters const * params); uint32_t const requested_ip_address);
}; };

View File

@ -1,131 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include "ip4.h"
#include "udp4.h"
#include "dhcp4.h"
#include "eth.h"
#include "packet.h"
#include "interface.h"
#include "sock.h"
int main()
{
int sock = sock::create(67);
char const * interface_name = "enp175s0";
int ifa_index = sock::interface_index(sock, interface_name);
sock::bind_interface(sock, ifa_index);
uint8_t eth_source_address[6];
sock::interface_address(sock, interface_name, eth_source_address);
packet::packet p{};
dhcp4::options options{};
static uint8_t recvbuf[65536];
static uint8_t sendbuf[16384];
uint32_t ip4_client_address = ip4::fromstr("10.0.0.50");
uint32_t ip4_server_address = ip4::fromstr("10.0.0.5");
uint32_t ip4_subnet_mask = ip4::fromstr("255.255.255.0");
uint32_t ip4_router = ip4::fromstr("10.0.0.5");
uint32_t ip4_domain_name_server = ip4::fromstr("8.8.8.8");
while (true) {
//////////////////////////////////////////////////////////////////////
// dhcp recv
//////////////////////////////////////////////////////////////////////
{
struct sockaddr_ll recv_address;
int flags = 0;
socklen_t socklen = (sizeof (struct sockaddr_ll));
ssize_t rret = recvfrom(sock, recvbuf, (sizeof (recvbuf)), flags,
(struct sockaddr *)&recv_address, &socklen);
if (rret < 0) {
perror("recvfrom");
exit(EXIT_FAILURE);
}
packet::parse(recvbuf, rret, &p);
int dhcp4_options_length = rret - (packet::dhcp4_offset + (offsetof (dhcp4::message, options)));
dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options);
printf("dhcp4 op: %d\n", p.dhcp4->op);
printf("message type: %s\n", dhcp4::message_type_tostr(options.message_type));
printf("transaction id: %08x\n", ntohl(p.dhcp4->xid));
}
if (options.message_type == dhcp4::message_type::dhcpdiscover) {
dhcp4::message_parameters params = {
.your_ip_address = ip4_client_address,
.next_server_ip_address = ip4_server_address,
.server_identifier = ip4_server_address,
.subnet_mask = ip4_subnet_mask,
.router = ip4_router,
.domain_name_server = ip4_domain_name_server,
};
uint8_t const * eth_destination_address = p.eth->source_address;
uint32_t ip4_source_address = ip4_server_address;
uint32_t ip4_destination_address = ip4_client_address;
uint32_t dhcp_transaction_id = ntohl(p.dhcp4->xid);
int length = packet::make(sendbuf,
dhcp4::op::bootreply,
eth_source_address,
eth_destination_address,
eth_destination_address, // eth_client_address
ip4_source_address,
ip4_destination_address,
67,
68,
dhcp_transaction_id,
dhcp4::message_type::dhcpoffer,
&params);
sock::send(sock, ifa_index, sendbuf, length, eth_destination_address);
}
if (options.message_type == dhcp4::message_type::dhcprequest) {
printf("requested ip address: %s\n", ip4::tostr(options.requested_ip_address));
if (options.requested_ip_address != ip4_client_address) {
printf("should NAK\n");
continue;
}
dhcp4::message_parameters params = {
.your_ip_address = ip4_client_address,
.next_server_ip_address = ip4_server_address,
.server_identifier = ip4_server_address,
.subnet_mask = ip4_subnet_mask,
.router = ip4_router,
.domain_name_server = ip4_domain_name_server,
};
uint8_t const * eth_destination_address = p.eth->source_address;
uint32_t ip4_source_address = ip4_server_address;
uint32_t ip4_destination_address = ip4_client_address;
uint32_t dhcp_transaction_id = ntohl(p.dhcp4->xid);
int length = packet::make(sendbuf,
dhcp4::op::bootreply,
eth_source_address,
eth_destination_address,
eth_destination_address, // eth_client_address
ip4_source_address,
ip4_destination_address,
67,
68,
dhcp_transaction_id,
dhcp4::message_type::dhcpack,
&params);
sock::send(sock, ifa_index, sendbuf, length, eth_destination_address);
}
}
}

192
sock.cpp
View File

@ -1,192 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include "sock.h"
namespace sock {
//////////////////////////////////////////////////////////////////////
// socket filter
//////////////////////////////////////////////////////////////////////
void attach_udp_filter(int sock, uint32_t destination_port)
{
struct sock_filter filter[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 6, 0x00000011 },
{ 0x28, 0, 0, 0x00000014 },
{ 0x45, 4, 0, 0x00001fff },
{ 0xb1, 0, 0, 0x0000000e },
{ 0x48, 0, 0, 0x00000010 },
{ 0x15, 0, 1, destination_port },
{ 0x06, 0, 0, 0x00040000 },
{ 0x06, 0, 0, 0000000000 },
};
struct sock_fprog fprog = {
.len = sizeof(filter) / sizeof(filter[0]),
.filter = filter,
};
int ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, (sizeof (fprog)));
if (ret < 0) {
perror("setsockopt(SO_ATTACH_FILTER)");
exit(EXIT_FAILURE);
}
}
//////////////////////////////////////////////////////////////////////
// fake socket
//////////////////////////////////////////////////////////////////////
int create_fake_socket(int port) {
int sf = socket(AF_INET, SOCK_DGRAM, 0);
if (sf < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// this has the effect of inhibiting linux's generation of icmp
// "destination unreachable" packets
struct sockaddr_in bind_addr_in = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr = { .s_addr = INADDR_ANY },
};
int bret_in = bind(sf, (struct sockaddr *)&bind_addr_in, (sizeof (struct sockaddr_in)));
if (bret_in < 0) {
perror("bind in");
exit(EXIT_FAILURE);
}
return sf;
}
//////////////////////////////////////////////////////////////////////
// create
//////////////////////////////////////////////////////////////////////
int create(int port)
{
int sock = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
if (sock < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
//////////////////////////////////////////////////////////////////////
// broadcast
//////////////////////////////////////////////////////////////////////
int enable = 1;
int ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &enable, (sizeof (int)));
if (ret < 0) {
perror("setsockopt(SO_BROADCAST)");
exit(EXIT_FAILURE);
}
//////////////////////////////////////////////////////////////////////
// dhcp_filter
//////////////////////////////////////////////////////////////////////
attach_udp_filter(sock, port);
//////////////////////////////////////////////////////////////////////
// fake socket
//////////////////////////////////////////////////////////////////////
create_fake_socket(port);
return sock;
}
//////////////////////////////////////////////////////////////////////
// bind
//////////////////////////////////////////////////////////////////////
void bind_interface(int sock, int ifa_index)
{
struct sockaddr_ll bind_addr_ll = {
.sll_family = AF_PACKET,
.sll_protocol = htons(ETH_P_IP),
.sll_ifindex = ifa_index,
};
int bret_ll = bind(sock, (struct sockaddr *)&bind_addr_ll, (sizeof (struct sockaddr_ll)));
if (bret_ll < 0) {
perror("bind ll");
exit(EXIT_FAILURE);
}
}
//////////////////////////////////////////////////////////////////////
// send
//////////////////////////////////////////////////////////////////////
void send(int sock,
int interface_index,
void * buf,
int length,
uint8_t const * eth_destination_address)
{
struct sockaddr_ll socket_address;
socket_address.sll_ifindex = interface_index;
socket_address.sll_halen = ETH_ALEN;
memcpy(socket_address.sll_addr, eth_destination_address, 6);
int flags = 0;
int sret = sendto(sock, buf, length, flags,
(struct sockaddr *)&socket_address, sizeof(struct sockaddr_ll));
if (sret < 0) {
perror("sendto");
exit(EXIT_FAILURE);
}
}
//////////////////////////////////////////////////////////////////////
// interface index
//////////////////////////////////////////////////////////////////////
int interface_index(int sock, char const * interface_name)
{
struct ifreq if_index;
memset(&if_index, 0, (sizeof (struct ifreq)));
strncpy(if_index.ifr_name, interface_name, IFNAMSIZ - 1);
int iret = ioctl(sock, SIOCGIFINDEX, &if_index);
if (iret < 0) {
perror("ioctl(SIOCGIFINDEX)");
exit(EXIT_FAILURE);
}
int ifa_index = if_index.ifr_ifindex;
printf("interface index %d\n", ifa_index);
return ifa_index;
}
//////////////////////////////////////////////////////////////////////
// interface address
//////////////////////////////////////////////////////////////////////
void interface_address(int sock, char const * interface_name, uint8_t * hardware_address)
{
struct ifreq if_hwaddr;
memset(&if_hwaddr, 0, sizeof(struct ifreq));
strncpy(if_hwaddr.ifr_name, interface_name, IFNAMSIZ - 1);
int hret = ioctl(sock, SIOCGIFHWADDR, &if_hwaddr);
if (hret < 0) {
perror("ioctl(SIOCGIFHWADDR)");
exit(EXIT_FAILURE);
}
printf("hardware address %02x:%02x:%02x:%02x:%02x:%02x\n",
(uint8_t)if_hwaddr.ifr_hwaddr.sa_data[0], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[1],
(uint8_t)if_hwaddr.ifr_hwaddr.sa_data[2], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[3],
(uint8_t)if_hwaddr.ifr_hwaddr.sa_data[4], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[5]);
memcpy(hardware_address, if_hwaddr.ifr_hwaddr.sa_data, 6);
}
}

21
sock.h
View File

@ -1,21 +0,0 @@
#pragma once
#include <stdint.h>
namespace sock {
int create(int port);
void bind_interface(int sock, int ifa_index);
void send(int sock,
int interface_index,
void * buf,
int length,
uint8_t const * eth_destination_address);
int interface_index(int sock, char const * interface_name);
void interface_address(int sock, char const * interface_name, uint8_t * hardware_address);
}