factor out client/server-agnostic code
This commit is contained in:
parent
395bb5c764
commit
0f8043893d
3
Makefile
3
Makefile
@ -19,7 +19,8 @@ OBJS = \
|
|||||||
udp4.o \
|
udp4.o \
|
||||||
eth.o \
|
eth.o \
|
||||||
rtnetlink.o \
|
rtnetlink.o \
|
||||||
interface.o
|
interface.o \
|
||||||
|
sock.o
|
||||||
|
|
||||||
all: client test2
|
all: client test2
|
||||||
|
|
||||||
|
|||||||
194
client.cpp
194
client.cpp
@ -7,13 +7,7 @@
|
|||||||
|
|
||||||
#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"
|
||||||
@ -21,167 +15,35 @@
|
|||||||
#include "eth.h"
|
#include "eth.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
|
#include "sock.h"
|
||||||
void interface_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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void attach_dhcp_filter(int sock)
|
|
||||||
{
|
|
||||||
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, 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));
|
||||||
|
|
||||||
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";
|
|
||||||
|
|
||||||
struct ifreq if_index;
|
|
||||||
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();
|
uint32_t dhcp_transaction_id = rand();
|
||||||
|
|
||||||
uint8_t eth_source_address[6] = {};
|
static uint8_t buf[16384];
|
||||||
memcpy(eth_source_address, if_hwaddr.ifr_hwaddr.sa_data, 6);
|
|
||||||
|
int sock = sock::create(68);
|
||||||
|
|
||||||
|
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];
|
||||||
|
sock::interface_address(sock, interface_name, eth_source_address);
|
||||||
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;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// dhcp send discover
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
{
|
||||||
|
dhcp4::message_parameters params = {
|
||||||
|
};
|
||||||
|
|
||||||
int length = packet::make(buf,
|
int length = packet::make(buf,
|
||||||
eth_source_address,
|
eth_source_address,
|
||||||
eth_destination_address,
|
eth_destination_address,
|
||||||
@ -189,9 +51,10 @@ int main()
|
|||||||
ip4_destination_address,
|
ip4_destination_address,
|
||||||
dhcp_transaction_id,
|
dhcp_transaction_id,
|
||||||
dhcp4::message_type::dhcpdiscover,
|
dhcp4::message_type::dhcpdiscover,
|
||||||
0);
|
¶ms);
|
||||||
|
|
||||||
interface_send(s, ifa_index, buf, length, eth_destination_address);
|
sock::send(sock, ifa_index, buf, length, eth_destination_address);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// dhcp recv offer
|
// dhcp recv offer
|
||||||
@ -205,7 +68,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(s, recvbuf, (sizeof (recvbuf)), flags,
|
ssize_t rret = recvfrom(sock, recvbuf, (sizeof (recvbuf)), flags,
|
||||||
(struct sockaddr *)&recv_address, &socklen);
|
(struct sockaddr *)&recv_address, &socklen);
|
||||||
if (rret < 0) {
|
if (rret < 0) {
|
||||||
perror("recvfrom");
|
perror("recvfrom");
|
||||||
@ -233,6 +96,10 @@ int main()
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
{
|
{
|
||||||
|
dhcp4::message_parameters params = {
|
||||||
|
.requested_ip_address = p.dhcp4->yiaddr,
|
||||||
|
};
|
||||||
|
|
||||||
int length = packet::make(buf,
|
int length = packet::make(buf,
|
||||||
eth_source_address,
|
eth_source_address,
|
||||||
eth_destination_address,
|
eth_destination_address,
|
||||||
@ -240,9 +107,9 @@ int main()
|
|||||||
ip4_destination_address,
|
ip4_destination_address,
|
||||||
dhcp_transaction_id,
|
dhcp_transaction_id,
|
||||||
dhcp4::message_type::dhcprequest,
|
dhcp4::message_type::dhcprequest,
|
||||||
p.dhcp4->yiaddr);
|
¶ms);
|
||||||
|
|
||||||
interface_send(s, ifa_index, buf, length, eth_destination_address);
|
sock::send(sock, ifa_index, buf, length, eth_destination_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
@ -253,7 +120,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(s, recvbuf, (sizeof (recvbuf)), flags,
|
ssize_t rret = recvfrom(sock, recvbuf, (sizeof (recvbuf)), flags,
|
||||||
(struct sockaddr *)&recv_address, &socklen);
|
(struct sockaddr *)&recv_address, &socklen);
|
||||||
if (rret < 0) {
|
if (rret < 0) {
|
||||||
perror("recvfrom");
|
perror("recvfrom");
|
||||||
@ -318,7 +185,6 @@ int main()
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
close(dfd);
|
close(dfd);
|
||||||
close(s);
|
close(sock);
|
||||||
close(sf);
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|||||||
63
dhcp4.cpp
63
dhcp4.cpp
@ -8,12 +8,36 @@
|
|||||||
|
|
||||||
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,
|
||||||
uint32_t requested_ip_address)
|
message_parameters const * params)
|
||||||
{
|
{
|
||||||
memset(buf, 0, (sizeof (message)));
|
memset(buf, 0, (sizeof (message)));
|
||||||
message * msg = reinterpret_cast<message *>(buf);
|
message * msg = reinterpret_cast<message *>(buf);
|
||||||
@ -22,6 +46,10 @@ 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;
|
||||||
@ -39,24 +67,25 @@ 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 ||
|
||||||
uint8_t * prl = &msg->options[index];
|
dhcp_message_type == message_type::dhcprequest) {
|
||||||
int length = 3;
|
index = add_parameter_request_list(msg, index);
|
||||||
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 (requested_ip_address != 0) {
|
if (params->subnet_mask != 0) {
|
||||||
uint8_t * addr = &msg->options[index];
|
index = add_uint32(msg, index, option::subnet_mask, params->subnet_mask);
|
||||||
int length = 4;
|
}
|
||||||
index += 2 + length;
|
|
||||||
addr[0] = option::requested_ip_address;
|
if (params->router != 0) {
|
||||||
addr[1] = length;
|
index = add_uint32(msg, index, option::router, params->router);
|
||||||
memcpy(&addr[2], &requested_ip_address, 4);
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
|||||||
12
dhcp4.h
12
dhcp4.h
@ -75,12 +75,22 @@ namespace dhcp4 {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct message_parameters {
|
||||||
|
uint32_t your_ip_address;
|
||||||
|
uint32_t next_server_ip_address;
|
||||||
|
uint32_t dhcp_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,
|
||||||
uint32_t requested_ip_address);
|
message_parameters const * params);
|
||||||
|
|
||||||
char const * message_type_tostr(int message_type);
|
char const * message_type_tostr(int message_type);
|
||||||
|
|
||||||
|
|||||||
@ -10,3 +10,5 @@ namespace interface {
|
|||||||
uint32_t gateway);
|
uint32_t gateway);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
{ >(/X k5@/X Xo#",nq
|
||||||
|
/X 23{ >(R< H`H` H`H`D( >(T`&C.N#>
6
|
||||||
|
|||||||
@ -68,18 +68,20 @@ namespace packet {
|
|||||||
uint32_t const ip4_destination_address,
|
uint32_t const ip4_destination_address,
|
||||||
uint32_t const dhcp_transaction_id,
|
uint32_t const dhcp_transaction_id,
|
||||||
uint32_t const dhcp_message_type,
|
uint32_t const dhcp_message_type,
|
||||||
uint32_t const requested_ip_address)
|
dhcp4::message_parameters const * params)
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// 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]),
|
||||||
dhcp4::op::bootrequest,
|
dhcp4::op::bootrequest,
|
||||||
dhcp_transaction_id,
|
dhcp_transaction_id,
|
||||||
eth_source_address,
|
eth_source_address,
|
||||||
dhcp_message_type,
|
dhcp_message_type,
|
||||||
requested_ip_address);
|
params);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// eth
|
// eth
|
||||||
|
|||||||
2
packet.h
2
packet.h
@ -27,5 +27,5 @@ namespace packet {
|
|||||||
uint32_t const ip4_destination_address,
|
uint32_t const ip4_destination_address,
|
||||||
uint32_t const dhcp_transaction_id,
|
uint32_t const dhcp_transaction_id,
|
||||||
uint32_t const dhcp_message_type,
|
uint32_t const dhcp_message_type,
|
||||||
uint32_t const requested_ip_address);
|
dhcp4::message_parameters const * params);
|
||||||
};
|
};
|
||||||
|
|||||||
192
sock.cpp
Normal file
192
sock.cpp
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#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
Normal file
21
sock.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#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);
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user