작성일: 2023년 10월 10일
패킷 보내기 (Send a packet)
예제 코드
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <arpa/inet.h> |
| #include <linux/if_packet.h> |
| #include <linux/ip.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <net/if.h> |
| #include <netinet/ether.h> |
| #include <errno.h> |
| |
| |
| |
| #define MY_DEST_MAC0 0x52 |
| #define MY_DEST_MAC1 0x54 |
| #define MY_DEST_MAC2 0x00 |
| #define MY_DEST_MAC3 0xcf |
| #define MY_DEST_MAC4 0xab |
| #define MY_DEST_MAC5 0x76 |
| |
| |
| #define DEFAULT_IF "enp7s0" |
| |
| #define BUF_SIZ 1024 |
| |
| |
| int main(int argc, char *argv[]) |
| { |
| int sockfd; |
| int tx_len = 0; |
| char sendbuf[BUF_SIZ]; |
| char ifName[IFNAMSIZ]; |
| struct ifreq if_idx; |
| struct ifreq if_mac; |
| struct ether_header *eh = (struct ether_header *) sendbuf; |
| struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header)); |
| struct sockaddr_ll socket_address; |
| |
| |
| if (argc > 1) |
| { |
| strcpy(ifName, argv[1]); |
| } |
| else |
| { |
| strcpy(ifName, DEFAULT_IF); |
| } |
| |
| |
| if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) |
| { |
| printf("socket() error: %d (%s)\n", errno, strerror(errno)); |
| return 0; |
| } |
| |
| |
| memset(&if_idx, 0, sizeof(struct ifreq)); |
| strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1); |
| if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) |
| { |
| printf("ioctl(SIOCGIFINDEX, %s) error: %d (%s)\n", ifName, errno, strerror(errno)); |
| return 0; |
| } |
| |
| |
| memset(&if_mac, 0, sizeof(struct ifreq)); |
| strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1); |
| if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) |
| { |
| printf("ioctl(SIOCGIFHWADDR, %s) error: %d (%s)\n", ifName, errno, strerror(errno)); |
| return 0; |
| } |
| |
| |
| memset(sendbuf, 0, BUF_SIZ); |
| |
| |
| |
| |
| printf("( %s ) MAC address = ", ifName); |
| for (int idx = 0; idx < 6; idx++) |
| { |
| eh->ether_shost[idx] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[idx]; |
| printf("%02x", eh->ether_shost[idx]); |
| if (idx < 5) |
| { |
| printf(":"); |
| } |
| } |
| printf("\n"); |
| |
| |
| |
| |
| |
| eh->ether_shost[3] = 0x01; |
| eh->ether_shost[4] = 0x02; |
| eh->ether_shost[5] = 0x03; |
| |
| |
| eh->ether_dhost[0] = MY_DEST_MAC0; |
| eh->ether_dhost[1] = MY_DEST_MAC1; |
| eh->ether_dhost[2] = MY_DEST_MAC2; |
| eh->ether_dhost[3] = MY_DEST_MAC3; |
| eh->ether_dhost[4] = MY_DEST_MAC4; |
| eh->ether_dhost[5] = MY_DEST_MAC5; |
| |
| |
| eh->ether_type = htons(ETH_P_IP); |
| tx_len += sizeof(struct ether_header); |
| |
| |
| |
| iph->ihl = 20 >> 2; |
| iph->version = 4; |
| iph->protocol = IPPROTO_IP; |
| iph->saddr = inet_addr("10.1.1.10"); |
| iph->daddr = inet_addr("10.1.1.11"); |
| iph->tot_len = 46 + 32; |
| |
| tx_len += sizeof(struct iphdr); |
| |
| |
| for (char idx = 0; idx < 32; idx++) |
| { |
| sendbuf[tx_len++] = idx; |
| } |
| |
| |
| socket_address.sll_ifindex = if_idx.ifr_ifindex; |
| |
| socket_address.sll_halen = ETH_ALEN; |
| |
| socket_address.sll_addr[0] = MY_DEST_MAC0; |
| socket_address.sll_addr[1] = MY_DEST_MAC1; |
| socket_address.sll_addr[2] = MY_DEST_MAC2; |
| socket_address.sll_addr[3] = MY_DEST_MAC3; |
| socket_address.sll_addr[4] = MY_DEST_MAC4; |
| socket_address.sll_addr[5] = MY_DEST_MAC5; |
| |
| |
| if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0) |
| printf("Send failed\n"); |
| |
| return 0; |
| } |
패킷 받기 (Receive a packet)
예제 코드
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <unistd.h> |
| #include <arpa/inet.h> |
| #include <linux/if_packet.h> |
| #include <linux/ip.h> |
| #include <linux/udp.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <net/if.h> |
| #include <netinet/ether.h> |
| #include <errno.h> |
| |
| #define ETHER_TYPE 0x0800 |
| |
| #define DEFAULT_IF "enp7s0" |
| #define BUF_SIZ 1024 |
| |
| int main(int argc, char *argv[]) |
| { |
| char sender[INET6_ADDRSTRLEN]; |
| int sockfd, ret; |
| int sockopt; |
| ssize_t pktbytes; |
| struct ifreq ifopts; |
| struct ifreq if_ip; |
| struct sockaddr_storage peer_addr; |
| uint8_t buf[BUF_SIZ]; |
| char ifName[IFNAMSIZ]; |
| |
| |
| if (argc > 1) |
| { |
| strcpy(ifName, argv[1]); |
| } |
| else |
| { |
| strcpy(ifName, DEFAULT_IF); |
| } |
| |
| |
| struct ether_header *eh = (struct ether_header *) buf; |
| struct iphdr *iph = (struct iphdr *) (buf + sizeof(struct ether_header)); |
| struct udphdr *udph = (struct udphdr *) (buf + sizeof(struct iphdr) + sizeof(struct ether_header)); |
| |
| if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) |
| { |
| printf("socket(PF_PACKET, SOCK_RAW, ETHER_TYPE) error: %d (%s)\n", errno, strerror(errno)); |
| return -1; |
| } |
| |
| |
| strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1); |
| ioctl(sockfd, SIOCGIFFLAGS, &ifopts); |
| ifopts.ifr_flags |= IFF_PROMISC; |
| ioctl(sockfd, SIOCSIFFLAGS, &ifopts); |
| if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) { |
| printf("setsockopt(SO_REUSEADDR) error: %d (%s)\n", errno, strerror(errno)); |
| close(sockfd); |
| exit(0); |
| } |
| |
| |
| if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) { |
| printf("setsockopt(SO_BINDTODEVICE, %s) error: %d (%s)\n", ifName, errno, strerror(errno)); |
| close(sockfd); |
| exit(0); |
| } |
| |
| repeat: |
| printf("\nWaiting to recvfrom...\n"); |
| pktbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL); |
| printf(" Got packet %lu bytes\n", pktbytes); |
| |
| printf("Destination MAC address = "); |
| for (int idx = 0; idx < 6; idx++) |
| { |
| printf("%02x", eh->ether_dhost[idx]); |
| if (idx < 5) |
| { |
| printf(":"); |
| } |
| } |
| printf("\n"); |
| |
| |
| ((struct sockaddr_in *)&peer_addr)->sin_addr.s_addr = iph->saddr; |
| inet_ntop(AF_INET, &((struct sockaddr_in*)&peer_addr)->sin_addr, sender, sizeof sender); |
| |
| |
| memset(&if_ip, 0, sizeof(struct ifreq)); |
| strncpy(if_ip.ifr_name, ifName, IFNAMSIZ-1); |
| if (ioctl(sockfd, SIOCGIFADDR, &if_ip) >= 0) { |
| printf("Source IP: %s\n My IP: %s\n", sender, |
| inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr)); |
| |
| if (strcmp(sender, inet_ntoa(((struct sockaddr_in *)&if_ip.ifr_addr)->sin_addr)) == 0) { |
| printf("but I sent it :(\n"); |
| ret = -1; |
| goto done; |
| } |
| } |
| |
| |
| ret = ntohs(udph->len) - sizeof(struct udphdr); |
| |
| |
| printf("\tData:"); |
| for (int idx = 0; idx < pktbytes; idx++) |
| { |
| printf("%02x ", buf[idx]); |
| } |
| printf("\n"); |
| |
| done: |
| goto repeat; |
| |
| close(sockfd); |
| return ret; |
| } |