Compare commits

..

3 Commits

Author SHA1 Message Date
395bb5c764 dns configuration 2026-08-19 23:45:45 -05:00
79b7ba2832 network interface configuration 2026-08-19 23:39:38 -05:00
c9bb6a5965 newroute 2026-08-19 22:38:09 -05:00
11 changed files with 466 additions and 88 deletions

View File

@ -18,7 +18,8 @@ OBJS = \
packet.o \ packet.o \
udp4.o \ udp4.o \
eth.o \ eth.o \
rtnetlink.o rtnetlink.o \
interface.o
all: client test2 all: client test2

View File

@ -2,8 +2,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <stddef.h>
#include <time.h> #include <time.h>
#include <fcntl.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -17,64 +19,8 @@
#include "udp4.h" #include "udp4.h"
#include "dhcp4.h" #include "dhcp4.h"
#include "eth.h" #include "eth.h"
#include "packet.h"
int make_packet(uint8_t * buf, #include "interface.h"
uint8_t const * eth_source_address,
uint8_t const * eth_destination_address,
uint32_t const ip4_source_address,
uint32_t const ip4_destination_address,
uint32_t const dhcp_transaction_id,
uint32_t const dhcp_message_type)
{
//////////////////////////////////////////////////////////////////////
// dhcp4
//////////////////////////////////////////////////////////////////////
int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)) + (sizeof (udp4::header));
int dhcp4_length = dhcp4::make_message(reinterpret_cast<void *>(&buf[dhcp4_offset]),
dhcp4::op::bootrequest,
dhcp_transaction_id,
eth_source_address,
dhcp_message_type);
//////////////////////////////////////////////////////////////////////
// eth
//////////////////////////////////////////////////////////////////////
int eth_offset = 0;
eth::header * eth_header = reinterpret_cast<eth::header *>(&buf[eth_offset]);
memcpy(eth_header->destination_address, eth_destination_address, 6);
memcpy(eth_header->source_address, eth_source_address, 6);
eth_header->ether_type = htons(0x0800);
//////////////////////////////////////////////////////////////////////
// ip4
//////////////////////////////////////////////////////////////////////
int ip4_offset = (sizeof (eth::header));
int ip4_payload_length = dhcp4_length + (sizeof (udp4::header));
int ip4_identification = 55179;
ip4::make_header(reinterpret_cast<void *>(&buf[ip4_offset]),
ip4_payload_length,
ip4_identification,
ip4_source_address,
ip4_destination_address);
//////////////////////////////////////////////////////////////////////
// udp4
//////////////////////////////////////////////////////////////////////
int udp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header));
udp4::make_header(reinterpret_cast<void *>(&buf[udp4_offset]),
htons(68),
htons(67),
ip4_source_address,
ip4_destination_address,
&buf[dhcp4_offset],
dhcp4_length);
return dhcp4_offset + dhcp4_length;
}
void interface_send(int sock, void interface_send(int sock,
int interface_index, int interface_index,
@ -161,7 +107,8 @@ int main()
perror("ioctl(SIOCGIFINDEX)"); perror("ioctl(SIOCGIFINDEX)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("interface index %d\n", if_index.ifr_ifindex); int ifa_index = if_index.ifr_ifindex;
printf("interface index %d\n", ifa_index);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// interface address // interface address
@ -184,21 +131,46 @@ int main()
// bind // bind
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
struct sockaddr_ll bind_addr = { struct sockaddr_ll bind_addr_ll = {
.sll_family = AF_PACKET, .sll_family = AF_PACKET,
.sll_protocol = htons(ETH_P_ALL), .sll_protocol = htons(ETH_P_IP),
.sll_ifindex = if_index.ifr_ifindex, .sll_ifindex = ifa_index,
}; };
int bret = bind(s, (struct sockaddr *)&bind_addr, (sizeof (struct sockaddr_ll))); int bret_ll = bind(s, (struct sockaddr *)&bind_addr_ll, (sizeof (struct sockaddr_ll)));
if (bret < 0) { if (bret_ll < 0) {
perror("bind"); perror("bind ll");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
attach_dhcp_filter(s); attach_dhcp_filter(s);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// send // 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();
@ -210,24 +182,143 @@ int main()
uint32_t ip4_source_address = 0x00000000; uint32_t ip4_source_address = 0x00000000;
uint32_t ip4_destination_address = 0xffffffff; uint32_t ip4_destination_address = 0xffffffff;
int length = make_packet(buf, int length = packet::make(buf,
eth_source_address, eth_source_address,
eth_destination_address, eth_destination_address,
ip4_source_address, ip4_source_address,
ip4_destination_address, ip4_destination_address,
dhcp_transaction_id, dhcp_transaction_id,
dhcp4::message_type::dhcpdiscover); dhcp4::message_type::dhcpdiscover,
0);
interface_send(s, if_index.ifr_ifindex, buf, length, eth_destination_address); interface_send(s, ifa_index, buf, length, eth_destination_address);
//////////////////////////////////////////////////////////////////////
// dhcp recv offer
//////////////////////////////////////////////////////////////////////
packet::packet p{};
dhcp4::options options{};
uint8_t recvbuf[65536]; uint8_t recvbuf[65536];
struct sockaddr_ll recv_address;
int flags = 0;
socklen_t socklen = (sizeof (struct sockaddr_ll));
ssize_t ret = recvfrom(s, recvbuf, 16384, flags,
(struct sockaddr *)&recv_address, &socklen);
printf("recv ret %ld\n", ret);
{
struct sockaddr_ll recv_address;
int flags = 0;
socklen_t socklen = (sizeof (struct sockaddr_ll));
ssize_t rret = recvfrom(s, recvbuf, (sizeof (recvbuf)), flags,
(struct sockaddr *)&recv_address, &socklen);
if (rret < 0) {
perror("recvfrom");
exit(EXIT_FAILURE);
}
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)));
dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &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(options.message_type == dhcp4::message_type::dhcpoffer);
}
//////////////////////////////////////////////////////////////////////
// dhcp send request
//////////////////////////////////////////////////////////////////////
{
int length = packet::make(buf,
eth_source_address,
eth_destination_address,
ip4_source_address,
ip4_destination_address,
dhcp_transaction_id,
dhcp4::message_type::dhcprequest,
p.dhcp4->yiaddr);
interface_send(s, ifa_index, buf, length, eth_destination_address);
}
//////////////////////////////////////////////////////////////////////
// dhcp recv ack
//////////////////////////////////////////////////////////////////////
{
struct sockaddr_ll recv_address;
int flags = 0;
socklen_t socklen = (sizeof (struct sockaddr_ll));
ssize_t rret = recvfrom(s, recvbuf, (sizeof (recvbuf)), flags,
(struct sockaddr *)&recv_address, &socklen);
if (rret < 0) {
perror("recvfrom");
exit(EXIT_FAILURE);
}
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)));
dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &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(options.message_type == dhcp4::message_type::dhcpack);
}
//////////////////////////////////////////////////////////////////////
// interface configure
//////////////////////////////////////////////////////////////////////
uint32_t mask = ntohl(options.subnet_mask);
uint8_t prefix_length = 32 - __builtin_ctz(mask);
printf("prefix_length %d\n", prefix_length);
interface::configure(ifa_index,
prefix_length,
p.dhcp4->yiaddr,
options.router);
//////////////////////////////////////////////////////////////////////
// dns configure
//////////////////////////////////////////////////////////////////////
int dfd = open("/etc/resolv.conf", O_CREAT | O_WRONLY | O_TRUNC);
if (dfd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
char dbuf[1024];
int dbuflen = snprintf(dbuf, (sizeof (dbuf)), "nameserver %s\n",
ip4::tostr(options.domain_name_server));
if (dbuflen < 0) {
perror("snprintf");
exit(EXIT_FAILURE);
}
ssize_t dret = write(dfd, dbuf, dbuflen);
if (dret < 0) {
perror("write");
exit(EXIT_FAILURE);
}
//////////////////////////////////////////////////////////////////////
// exit
//////////////////////////////////////////////////////////////////////
close(dfd);
close(s); close(s);
close(sf);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View File

@ -1,5 +1,6 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -11,7 +12,8 @@ namespace dhcp4 {
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)
{ {
memset(buf, 0, (sizeof (message))); memset(buf, 0, (sizeof (message)));
message * msg = reinterpret_cast<message *>(buf); message * msg = reinterpret_cast<message *>(buf);
@ -48,6 +50,15 @@ namespace dhcp4 {
prl[4] = option::domain_name_server; prl[4] = option::domain_name_server;
} }
if (requested_ip_address != 0) {
uint8_t * addr = &msg->options[index];
int length = 4;
index += 2 + length;
addr[0] = option::requested_ip_address;
addr[1] = length;
memcpy(&addr[2], &requested_ip_address, 4);
}
uint8_t * end = &msg->options[index]; uint8_t * end = &msg->options[index];
index += 1; index += 1;
end[0] = 255; end[0] = 255;

View File

@ -51,6 +51,7 @@ namespace dhcp4 {
router = 3, router = 3,
domain_name_server = 6, domain_name_server = 6,
broadcast_address = 28, broadcast_address = 28,
requested_ip_address = 50,
ip_address_lease_time = 51, ip_address_lease_time = 51,
option_overload = 52, option_overload = 52,
message_type = 53, message_type = 53,
@ -78,7 +79,8 @@ namespace dhcp4 {
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);
char const * message_type_tostr(int message_type); char const * message_type_tostr(int message_type);

114
interface.cpp Normal file
View File

@ -0,0 +1,114 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/rtnetlink.h>
#include "ip4.h"
#include "rtnetlink.h"
#include "interface.h"
namespace interface {
static void newaddr(int fd,
uint32_t ifa_index, uint8_t ifa_prefixlen, uint32_t local, uint32_t address)
{
int dret = rtnetlink::send_typeaddr(fd, RTM_NEWADDR, ifa_index,
ifa_prefixlen, local, address);
if (dret < 0) {
exit(EXIT_FAILURE);
}
int eret = rtnetlink::handle_error(fd);
if (eret < 0) {
exit(EXIT_FAILURE);
}
}
static void deladdr(int fd,
uint32_t ifa_index, uint8_t ifa_prefixlen, uint32_t local, uint32_t address)
{
int dret = rtnetlink::send_typeaddr(fd, RTM_DELADDR, ifa_index,
ifa_prefixlen, local, address);
if (dret < 0) {
exit(EXIT_FAILURE);
}
int eret = rtnetlink::handle_error(fd);
if (eret < 0) {
exit(EXIT_FAILURE);
}
}
static void newroute(int fd,
uint32_t ifa_index, uint32_t gateway)
{
int dret = rtnetlink::send_newroute(fd, ifa_index, gateway);
if (dret < 0) {
exit(EXIT_FAILURE);
}
int eret = rtnetlink::handle_error(fd);
if (eret < 0) {
exit(EXIT_FAILURE);
}
}
static void flush_addresses(int fd,
uint32_t ifa_index)
{
int grets = rtnetlink::send_getaddr(fd, ifa_index);
if (grets < 0) {
exit(EXIT_FAILURE);
}
const int out_length = 64;
rtnetlink::newaddr out[out_length];
int greth = rtnetlink::handle_getaddr(fd, ifa_index, out, out_length);
if (greth < 0) {
exit(EXIT_FAILURE);
}
for (int i = 0; i < greth; i++) {
printf("deladdr[%d]:\n", i);
printf(" prefixlen %d\n", out[i].ifa_prefixlen);
printf(" local %s\n", ip4::tostr(out[i].local));
printf(" address %s\n", ip4::tostr(out[i].address));
deladdr(fd, ifa_index, out[i].ifa_prefixlen, out[i].local, out[i].address);
}
}
void configure(uint32_t ifa_index,
uint8_t ifa_prefixlen,
uint32_t address,
uint32_t gateway)
{
//////////////////////////////////////////////////////////////////////
// netlink socket
//////////////////////////////////////////////////////////////////////
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
struct sockaddr_nl bsa = { .nl_family = AF_NETLINK };
int ret = bind(fd, (struct sockaddr *)&bsa, (sizeof (sockaddr_nl)));
if (ret < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
flush_addresses(fd, ifa_index);
newaddr(fd,
ifa_index, ifa_prefixlen, address, address);
newroute(fd,
ifa_index, gateway);
}
}

12
interface.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
namespace interface {
void configure(uint32_t ifa_index,
uint8_t ifa_prefixlen,
uint32_t address,
uint32_t gateway);
}

View File

@ -10,6 +10,7 @@
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <net/if.h> #include <net/if.h>
#include <arpa/inet.h>
#include "ip4.h" #include "ip4.h"
#include "rtnetlink.h" #include "rtnetlink.h"
@ -43,7 +44,6 @@ int main()
// interface index // interface index
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
char const * interface_name = "wlp174s0";
struct ifreq if_index = {}; struct ifreq if_index = {};
strncpy(if_index.ifr_name, interface_name, IFNAMSIZ - 1); strncpy(if_index.ifr_name, interface_name, IFNAMSIZ - 1);
int iret = ioctl(fd, SIOCGIFINDEX, &if_index); int iret = ioctl(fd, SIOCGIFINDEX, &if_index);
@ -103,5 +103,22 @@ int main()
} }
} }
// newroute
{
printf("newroute\n");
uint32_t gateway;
int ret = inet_pton(AF_INET, "192.168.1.1", (void *)&gateway);
assert(ret == 1);
int dret = rtnetlink::send_newroute(fd, if_index.ifr_ifindex, gateway);
if (dret < 0) {
exit(EXIT_FAILURE);
}
int eret = rtnetlink::handle_error(fd);
if (eret < 0) {
exit(EXIT_FAILURE);
}
}
return 0; return 0;
} }

View File

@ -1,4 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -59,4 +60,60 @@ namespace packet {
p->udp4 = udp4_header; p->udp4 = udp4_header;
p->dhcp4 = dhcp4_message; p->dhcp4 = dhcp4_message;
} }
int make(uint8_t * buf,
uint8_t const * eth_source_address,
uint8_t const * eth_destination_address,
uint32_t const ip4_source_address,
uint32_t const ip4_destination_address,
uint32_t const dhcp_transaction_id,
uint32_t const dhcp_message_type,
uint32_t const requested_ip_address)
{
//////////////////////////////////////////////////////////////////////
// dhcp4
//////////////////////////////////////////////////////////////////////
int dhcp4_length = dhcp4::make_message(reinterpret_cast<void *>(&buf[dhcp4_offset]),
dhcp4::op::bootrequest,
dhcp_transaction_id,
eth_source_address,
dhcp_message_type,
requested_ip_address);
//////////////////////////////////////////////////////////////////////
// eth
//////////////////////////////////////////////////////////////////////
eth::header * eth_header = reinterpret_cast<eth::header *>(&buf[eth_offset]);
memcpy(eth_header->destination_address, eth_destination_address, 6);
memcpy(eth_header->source_address, eth_source_address, 6);
eth_header->ether_type = htons(0x0800);
//////////////////////////////////////////////////////////////////////
// ip4
//////////////////////////////////////////////////////////////////////
int ip4_payload_length = dhcp4_length + (sizeof (udp4::header));
int ip4_identification = 55179;
ip4::make_header(reinterpret_cast<void *>(&buf[ip4_offset]),
ip4_payload_length,
ip4_identification,
ip4_source_address,
ip4_destination_address);
//////////////////////////////////////////////////////////////////////
// udp4
//////////////////////////////////////////////////////////////////////
udp4::make_header(reinterpret_cast<void *>(&buf[udp4_offset]),
htons(68),
htons(67),
ip4_source_address,
ip4_destination_address,
&buf[dhcp4_offset],
dhcp4_length);
return dhcp4_offset + dhcp4_length;
}
} }

View File

@ -19,4 +19,13 @@ namespace packet {
const int ip4_offset = (sizeof (eth::header)); const int ip4_offset = (sizeof (eth::header));
const int udp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)); const int udp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header));
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,
uint8_t const * eth_source_address,
uint8_t const * eth_destination_address,
uint32_t const ip4_source_address,
uint32_t const ip4_destination_address,
uint32_t const dhcp_transaction_id,
uint32_t const dhcp_message_type,
uint32_t const requested_ip_address);
}; };

View File

@ -18,7 +18,7 @@ static inline int align4(int len)
return (len + 3) & (~3); return (len + 3) & (~3);
} }
struct newaddr_msg { struct getaddr_msg {
struct nlmsghdr nl; struct nlmsghdr nl;
struct ifaddrmsg ifaddr; struct ifaddrmsg ifaddr;
}; };
@ -32,6 +32,15 @@ struct deladdr_msg {
} attr[2]; } attr[2];
}; };
struct newroute_msg {
struct nlmsghdr nl;
struct rtmsg rt;
struct {
struct rtattr rtattr;
uint32_t value;
} attr[2];
};
namespace rtnetlink { namespace rtnetlink {
bool parse_newaddr(uint8_t const * buf, ssize_t length, bool parse_newaddr(uint8_t const * buf, ssize_t length,
@ -127,9 +136,9 @@ namespace rtnetlink {
int send_getaddr(int fd, uint32_t ifa_index) int send_getaddr(int fd, uint32_t ifa_index)
{ {
const size_t message_length = (sizeof (struct newaddr_msg)); const size_t message_length = (sizeof (struct getaddr_msg));
struct newaddr_msg rtmmsg = { struct getaddr_msg rtmmsg = {
.nl = { .nl = {
.nlmsg_len = message_length, .nlmsg_len = message_length,
.nlmsg_type = RTM_GETADDR, .nlmsg_type = RTM_GETADDR,
@ -218,6 +227,59 @@ namespace rtnetlink {
return 0; return 0;
} }
int send_newroute(int fd, uint32_t ifa_index, uint32_t gateway)
{
const size_t message_length = (sizeof (struct newroute_msg));
struct newroute_msg rtmmsg = {
.nl = {
.nlmsg_len = message_length,
.nlmsg_type = RTM_NEWROUTE,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE,
.nlmsg_seq = 123456,
},
.rt = {
.rtm_family = AF_INET,
.rtm_table = RT_TABLE_MAIN,
.rtm_protocol = RTPROT_BOOT,
.rtm_scope = RT_SCOPE_UNIVERSE,
.rtm_type = RTN_UNICAST,
},
.attr = {
{
.rtattr = { .rta_len = 8, .rta_type = RTA_GATEWAY },
.value = gateway,
},
{
.rtattr = { .rta_len = 8, .rta_type = RTA_OIF },
.value = ifa_index,
}
}
};
struct iovec iov[1] = {
{
.iov_base = &rtmmsg,
.iov_len = message_length,
}
};
struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
struct msghdr msg = {
.msg_name = (void *)&addr,
.msg_namelen = (sizeof (sockaddr_nl)),
.msg_iov = iov,
.msg_iovlen = 1,
};
ssize_t sret = sendmsg(fd, &msg, 0);
if (sret < 0) {
perror("sendmsg");
return -1;
}
return 0;
}
int handle_error(int fd) int handle_error(int fd)
{ {
struct sockaddr_nl addr = { .nl_family = AF_NETLINK }; struct sockaddr_nl addr = { .nl_family = AF_NETLINK };

View File

@ -19,5 +19,7 @@ namespace rtnetlink {
int send_getaddr(int fd, uint32_t ifa_index); int send_getaddr(int fd, uint32_t ifa_index);
int send_typeaddr(int fd, uint16_t nlmsg_type, uint32_t ifa_index, uint8_t ifa_prefixlen, uint32_t local, uint32_t address); int send_typeaddr(int fd, uint16_t nlmsg_type, uint32_t ifa_index, uint8_t ifa_prefixlen, uint32_t local, uint32_t address);
int send_newroute(int fd, uint32_t ifa_index, uint32_t gateway);
int handle_error(int fd); int handle_error(int fd);
} }