dhcp/interface.cpp

115 lines
3.0 KiB
C++

#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);
}
}