use netlink api (legacy ioctl frontend)
This commit is contained in:
parent
c526033ad9
commit
bab44ceea9
1 changed files with 75 additions and 33 deletions
108
main.c
108
main.c
|
|
@ -3,8 +3,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <net/ethernet.h>
|
#include <net/ethernet.h>
|
||||||
#include <linux/if_packet.h>
|
#include <linux/if_packet.h>
|
||||||
|
|
@ -38,15 +41,17 @@ struct linkinterface {
|
||||||
uint8_t gateway[ETH_ALEN];
|
uint8_t gateway[ETH_ALEN];
|
||||||
|
|
||||||
int fd; // raw socket
|
int fd; // raw socket
|
||||||
|
int if_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct linkinterface* link_parse(const char* if_name, const char* host, const char* gateway) {
|
struct linkinterface* link_parse(const char* if_name, const char* gateway) {
|
||||||
struct linkinterface* link = (struct linkinterface*)malloc(sizeof(struct linkinterface));
|
struct linkinterface* link = (struct linkinterface*)malloc(sizeof(struct linkinterface));
|
||||||
link->if_name = strdup(if_name);
|
link->if_name = strdup(if_name);
|
||||||
link->if_len = strlen(link->if_name);
|
link->if_len = strlen(link->if_name);
|
||||||
|
|
||||||
parse_mac(host, link->host);
|
|
||||||
parse_mac(gateway, link->gateway);
|
parse_mac(gateway, link->gateway);
|
||||||
|
|
||||||
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_open(struct linkinterface* link) {
|
int link_open(struct linkinterface* link) {
|
||||||
|
|
@ -54,7 +59,25 @@ int link_open(struct linkinterface* link) {
|
||||||
if (link->fd < 0) {
|
if (link->fd < 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
setsockopt(link->fd, SOL_SOCKET, SO_BINDTODEVICE, link->if_name, link->if_name);
|
setsockopt(link->fd, SOL_SOCKET, SO_BINDTODEVICE, link->if_name, link->if_len);
|
||||||
|
|
||||||
|
// get interface index and MAC
|
||||||
|
struct ifreq netlink;
|
||||||
|
memset(&netlink, '\0', sizeof(netlink));
|
||||||
|
strncpy(netlink.ifr_ifrn.ifrn_name, link->if_name, IFNAMSIZ-1);
|
||||||
|
if (ioctl(link->fd, SIOCGIFINDEX, &netlink) < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
link->if_idx = netlink.ifr_ifru.ifru_ivalue; // index
|
||||||
|
|
||||||
|
memset(&netlink, '\0', sizeof(netlink));
|
||||||
|
strncpy(netlink.ifr_ifrn.ifrn_name, link->if_name, IFNAMSIZ-1);
|
||||||
|
if (ioctl(link->fd, SIOCGIFHWADDR, &netlink) < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memcpy(link->host, netlink.ifr_ifru.ifru_hwaddr.sa_data, ETH_ALEN); // MAC
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void link_free(struct linkinterface* link) {
|
void link_free(struct linkinterface* link) {
|
||||||
|
|
@ -63,24 +86,7 @@ void link_free(struct linkinterface* link) {
|
||||||
free(link);
|
free(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct arp_packet_s {
|
ssize_t link_send(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t len) {
|
||||||
struct ether_header ether;
|
|
||||||
|
|
||||||
uint16_t hrd; // Hardware address space (e.g., Ethernet, Packet Radio Net.)
|
|
||||||
uint16_t pro; // Protocol address space. For Ethernet hardware, this is from the set of type fields ether_typ$<protocol>.
|
|
||||||
uint8_t hln; // byte length of each hardware address
|
|
||||||
uint8_t pln; // byte length of each protocol address
|
|
||||||
uint16_t op; // opcode (ares_op$REQUEST | ares_op$REPLY)
|
|
||||||
uint8_t sha[ETH_ALEN]; // Hardware address of sender of this packet
|
|
||||||
uint8_t spa[4]; // Protocol address of sender of this packet
|
|
||||||
uint8_t tha[ETH_ALEN]; // Hardware address of sender of this packet
|
|
||||||
uint8_t tpa[4]; // Protocol address of sender of this packet
|
|
||||||
} __attribute__((packed)) arp_packet_t;
|
|
||||||
|
|
||||||
#define ARP_OP_REQUEST 0x01
|
|
||||||
#define ARP_OP_REPLY 0x02
|
|
||||||
|
|
||||||
int link_send(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t len) {
|
|
||||||
struct ether_header* ether = (struct ether_header*)packet;
|
struct ether_header* ether = (struct ether_header*)packet;
|
||||||
memcpy(ether->ether_shost, link->host, ETH_ALEN);
|
memcpy(ether->ether_shost, link->host, ETH_ALEN);
|
||||||
memcpy(ether->ether_dhost, link->gateway, ETH_ALEN);
|
memcpy(ether->ether_dhost, link->gateway, ETH_ALEN);
|
||||||
|
|
@ -89,7 +95,7 @@ int link_send(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t
|
||||||
return send(link->fd, packet, len, 0);
|
return send(link->fd, packet, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_recv(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t len) {
|
ssize_t link_recv(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t len) {
|
||||||
char buffer[MTU];
|
char buffer[MTU];
|
||||||
uint16_t want_type = htons(type);
|
uint16_t want_type = htons(type);
|
||||||
do {
|
do {
|
||||||
|
|
@ -117,23 +123,59 @@ int link_recv(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t
|
||||||
// TODO: timeout
|
// TODO: timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ARP_HW_ETHER 0x000F
|
||||||
|
#define ARP_PT_IP 0x0800
|
||||||
|
|
||||||
|
#define ARP_OP_REQUEST 1
|
||||||
|
#define ARP_OP_REPLY 2
|
||||||
|
|
||||||
|
// Inverse ARP
|
||||||
|
#define INARP_OP_REQUEST 8
|
||||||
|
#define INART_OP_REPLY 9
|
||||||
|
|
||||||
|
typedef struct arp_packet_s {
|
||||||
|
struct ether_header ether;
|
||||||
|
|
||||||
|
uint16_t hrd; // Hardware address space (e.g., Ethernet, Packet Radio Net.)
|
||||||
|
uint16_t pro; // Protocol address space. For Ethernet hardware, this is from the set of type fields ether_typ$<protocol>.
|
||||||
|
uint8_t hln; // byte length of each hardware address
|
||||||
|
uint8_t pln; // byte length of each protocol address
|
||||||
|
uint16_t op; // opcode (ares_op$REQUEST | ares_op$REPLY)
|
||||||
|
uint8_t sha[ETH_ALEN]; // Hardware address of sender of this packet
|
||||||
|
uint8_t spa[4]; // Protocol address of sender of this packet
|
||||||
|
uint8_t tha[ETH_ALEN]; // Hardware address of sender of this packet
|
||||||
|
uint8_t tpa[4]; // Protocol address of sender of this packet
|
||||||
|
} __attribute__((packed)) arp_packet_t;
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// ifname hostMAC gatewayMAC targetMAC
|
// ifname hostMAC gatewayMAC targetMAC
|
||||||
struct linkinterface* link = link_parse(argv[1], argv[2], argv[3]);
|
struct linkinterface* link = link_parse(argv[1], argv[2]);
|
||||||
|
|
||||||
uint8_t target[ETH_ALEN];
|
uint8_t target[ETH_ALEN];
|
||||||
parse_mac(argv[4], target);
|
parse_mac(argv[3], target);
|
||||||
|
|
||||||
link_open(link);
|
if (link_open(link) < 0) {
|
||||||
|
perror("link_open");
|
||||||
// test receive
|
return 1;
|
||||||
while (1) {
|
|
||||||
uint8_t packet[MTU];
|
|
||||||
ssize_t rd = recv(link->fd, packet, MTU, 0);
|
|
||||||
|
|
||||||
struct ether_header *ether = (struct ether_header *)&packet[0];
|
|
||||||
print_mac(ether->ether_shost);
|
|
||||||
}
|
}
|
||||||
|
print_mac(link->host);
|
||||||
|
|
||||||
|
uint8_t ip[4] = {192, 168, 100, 3};
|
||||||
|
|
||||||
|
// test arp send
|
||||||
|
arp_packet_t arp;
|
||||||
|
arp.hrd = htons(ARP_HW_ETHER);
|
||||||
|
arp.pro = htons(ARP_PT_IP);
|
||||||
|
arp.hln = htons(ETH_ALEN);
|
||||||
|
arp.pln = htons(4);
|
||||||
|
arp.op = htons(INARP_OP_REQUEST);
|
||||||
|
memcpy(arp.sha, link->host, ETH_ALEN);
|
||||||
|
memcpy(arp.spa, ip, 4);
|
||||||
|
memcpy(arp.tha, target, ETH_ALEN);
|
||||||
|
memset(arp.tpa, '\0', 4);
|
||||||
|
|
||||||
|
ssize_t sent = link_send(link, ETHERTYPE_ARP, (uint8_t*)&arp, sizeof(arp));
|
||||||
|
printf("sent %ld\n", sent);
|
||||||
|
|
||||||
link_free(link);
|
link_free(link);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue