diff --git a/main.c b/main.c index a650b30..b6ad4bf 100644 --- a/main.c +++ b/main.c @@ -3,8 +3,11 @@ #include #include #include +#include #include +#include #include +#include #include #include #include @@ -38,15 +41,17 @@ struct linkinterface { uint8_t gateway[ETH_ALEN]; 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)); link->if_name = strdup(if_name); link->if_len = strlen(link->if_name); - parse_mac(host, link->host); parse_mac(gateway, link->gateway); + + return link; } int link_open(struct linkinterface* link) { @@ -54,7 +59,25 @@ int link_open(struct linkinterface* link) { if (link->fd < 0) { 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) { @@ -63,24 +86,7 @@ void link_free(struct linkinterface* link) { free(link); } -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$. - 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) { +ssize_t link_send(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t len) { struct ether_header* ether = (struct ether_header*)packet; memcpy(ether->ether_shost, link->host, 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); } -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]; uint16_t want_type = htons(type); do { @@ -117,23 +123,59 @@ int link_recv(struct linkinterface* link, uint16_t type, uint8_t* packet, size_t // 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$. + 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) { // 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]; - parse_mac(argv[4], target); + parse_mac(argv[3], target); - link_open(link); - - // test receive - 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); + if (link_open(link) < 0) { + perror("link_open"); + return 1; } + 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); return 0;