Socketii "raw", din familia de protocoale PF_PACKET sunt folositi pentru a receptiona sau trimite pachete "raw" direct la nivelul dispozitivului fizic (nivelul OSI 2). Sunt folositi pentru a implementa protocoale direct in user-space fie pentru a le testa fie pentru ca protocolul nu are rost sa fie implementat in kernel. Aceasta familie de protocoale pune la dispozitie doua tipuri de socketi:
- SOCK_RAW - pachetele sunt prezentate utilizatorului asa cum sunt primite de la device driver (i.e. cu tot cu headerul de nivel 2); de asemenea la trimiterea unui pachet printr-un socket de acest tip pachetele sunt trimise nemodificate astfel incat trebuie sa contina si headerul
- SOCK_DGRAM - pachetele sunt prezentate utilizatorului fara headerul de nivel 2; pachetelor trimise pritr-un socket de acest tip li se va adauga headerul de nivel 2; practic utilizatorul vede doar continul pachetului
Socketii "raw" sunt creati la fel ca si socketii normali cu apelul de sistem socket:
packet_socket = socket(PF_PACKET, int socket_type, int protocol);unde socket_type poate fi SOCK_RAW sau SOCK_DGRAM iar protocol una din constantele definite in linux/if_ether.
Aplicatia de mai jos "asculta" toate pachetele care ajung in calculator si printeaza continutul lor, fie ca ii sunt adresate calculatorului sau nu.
#include "netinet/in.h"
#include "stdio.h"
#include "unistd.h"
#include "netpacket/packet.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "net/if.h"
#include "stdlib.h"
#include "sys/ioctl.h"
#include "string.h"
#include "net/if_arp.h"
#include "linux/if_ether.h"
int start(int proto) //eth_p_ip
{
int fd = socket(PF_PACKET, SOCK_DGRAM, htons(proto));
if (fd < 0)
{
perror("can't create protocol socket:");
return -1;
}
return fd;
}
int bind_socket(int fd, int interface, int protocol)
{
struct sockaddr_ll sock_info;
memset(&sock_info, 0, sizeof(sock_info));
sock_info.sll_family = AF_PACKET;
sock_info.sll_protocol = htons(protocol);
sock_info.sll_ifindex = interface;
if (bind(fd, (struct sockaddr *)&sock_info, sizeof(sock_info)))
{
perror("can't bind socket to i/f %m\n");
return -1;
}
return 0;
}
int find_interface(char *name)
{
struct ifreq ifr;
int iindex = 1;
int sock = socket(PF_PACKET, SOCK_RAW, 0);
ifr.ifr_ifindex = iindex;
while (ioctl(sock, SIOCGIFNAME, &ifr) == 0)
{
if (strcmp(ifr.ifr_name, name) == 0)
{
close(sock);
return iindex;
}
ifr.ifr_ifindex = ++iindex;
}
close(sock);
return -1;
}
int set_promisc(int fd, int ifn)
{
struct packet_mreq pack_info;
pack_info.mr_type = PACKET_MR_PROMISC;
pack_info.mr_alen = 0;
pack_info.mr_ifindex = ifn;
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &pack_info, sizeof(pack_info)))
{
printf("can't set promiscous mode\n");
return -1;
}
return 0;
}
int recv_packet(int sockfd, int *ifn, unsigned char macaddr[], unsigned char *data, int maxlen)
{
struct msghdr msg;
struct iovec iov;
struct sockaddr_ll sock_info;
int len;
memset(&msg, 0, sizeof(msg));
msg.msg_name = &sock_info;
msg.msg_namelen = sizeof(sock_info);
msg.msg_iovlen = 1;
msg.msg_iov = &iov;
iov.iov_len = maxlen;
iov.iov_base = data;
len = recvmsg(sockfd, &msg, 0);
*ifn = sock_info.sll_ifindex;
memcpy(macaddr, sock_info.sll_addr, 6);
return len;
}
int main()
{
int sockfd = start(ETH_P_IP);
int interface = find_interface("eth0");
int b = bind_socket(sockfd, interface, ETH_P_IP);
unsigned char *macaddr=(unsigned char *)malloc(256*sizeof(unsigned char)), *data= (unsigned char *)malloc(256*sizeof(unsigned char));
while (1) {
int promise = set_promisc(sockfd, interface);
int recv = recv_packet(sockfd, &interface, macaddr, data, 256), i;
for(i=0; i < 256;i++)
printf("%c",data[i]);
printf("\n");
}
return 0;
}
Nota
Fisierul va fi executat din pozitie de admin (in Linux: sudo su)
Niciun comentariu:
Trimiteți un comentariu