动机是我屋里有两台电脑,但到屋里只有一根外出网线,一台机子有双网卡,我就正好运用我前段学习的libpcap和libnet写了一个数据包转发的小工
具,把双网卡的机子模拟成一个交换机,使另一台机子能通过它访问外网,虽然用其它方法以能实现,但这正好是一个练习上面说的两个工具的好地方,还有以可免
除当双网卡机子不开机时,另一台机子只要直接接上外网的网线就行了,不用频繁的更改IP。
/* net data packet transmit tools
* liujx
* 2007-4-1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <netinet/ip.h>
#include <sys/time.h>
#include <net/ethernet.h>
#include <pthread.h>
#include <pcap.h>
#include <libnet.h>
#define IN_ETH "eth1"
char *dev_a, *dev_b;
pcap_t *pt_a, *pt_b;
pthread_t pid_a, pid_b;
libnet_t *net_a, *net_b;
static char errbuf[256];
void sigproc( int sig );
void* dev_a_capture( void *);
void dev_a_handle( u_char *devId, const struct pcap_pkthdr *h, const u_char *p );
void* dev_b_capture( void *);
void dev_b_handle( u_char *devId, const struct pcap_pkthdr *h, const u_char *p );
int main( int argc, char* argv[] )
{
/* regise signal ctrl+c stop capture */
signal( SIGINT, sigproc ) ;
/* init libnet */
net_a = libnet_init( LIBNET_LINK, "eth2", errbuf );
if( net_a == NULL )
{
fprintf(stderr, "libnet_init fail:%s ", errbuf );
return;
}
net_b = libnet_init( LIBNET_LINK, "eth1", errbuf );
if( net_a == NULL )
{
fprintf(stderr, "libnet_init fail:%s ", errbuf );
return;
}
/* create thread */
int status;
printf("create a ");
status = pthread_create( &pid_a, NULL, dev_a_capture, NULL );
if ( status != 0 )
{
printf( "pthread_create( A ) faile. ");
goto end;
}
printf("create b ");
status = pthread_create( &pid_b, NULL, dev_b_capture, NULL );
if ( status != 0 )
{
printf( "pthread_create( B ) faile. ");
goto end;
}
pthread_join( pid_a, NULL );
pthread_join( pid_b, NULL );
end:
pcap_close( pt_a );
pcap_close( pt_b );
return 0;
}
/* single processing function */
void sigproc( int sig )
{
pthread_cancel( pid_a );
pthread_cancel( pid_b );
pcap_close( pt_a );
pcap_close( pt_b );
libnet_destroy( net_a );
libnet_destroy( net_b );
printf("exit transmit. ");
exit(0);
}
/*receive eth1's packet and transmit to eth2 */
void* dev_a_capture(void *arg)
{
dev_a = pcap_lookupdev( errbuf );
if ( dev_a == NULL)
{
printf("pcap_lookupdev: %s ", errbuf );
exit( 0 );
}
printf("get dev: '%s' ", dev_a );
pt_a = pcap_open_live( dev_a, 8000, 1, 500, errbuf );
if( pt_a == NULL )
{
printf("pcap_open_live:%s ", errbuf );
exit(0);
}
for(;;)
{
int ret;
ret = pcap_dispatch( pt_a, 0, dev_a_handle, NULL);
if ( ret == -1 )
{
pcap_perror( pt_a, "pcap_dispatch err:");
}
}
}
void dev_a_handle( u_char *devId, const struct pcap_pkthdr *hdr, const u_char *packet )
{
//printf("%s,capture size :%d ",devId, hdr->caplen );
struct ether_header ehdr;
memcpy( &ehdr, packet, sizeof( struct ether_header ));
/* labpcap can capture all packet ,include self send packet.
* only transmit distination address is 221(eth2 MAC last bytes) or broadcast address,
* 221 is eth2 link host's MAC.
*/
if( ehdr.ether_shost[ETH_ALEN-1] == 221 )
{
return;
}
if( ehdr.ether_dhost[ETH_ALEN-1] == 221 || ehdr.ether_dhost[ETH_ALEN-1] == 255 )
{
printf("A src:%d, dst:%d ", ehdr.ether_shost[ETH_ALEN-1], ehdr.ether_dhost[ETH_ALEN-1] );
int c;
c = libnet_write_link( net_a, (u_char*)packet, hdr->caplen );
//printf("A write: %d ", c );
}
}
/* receive eth2's packet and transmit to eth1. */
void* dev_b_capture(void *arg)
{
//dev_b = pcap_lookupdev( errbuf );
dev_b = "eth2";
pt_b = pcap_open_live( dev_b, 8000, 1, 500, errbuf );
if( pt_b == NULL )
{
printf("pcap_open_live:%s ", errbuf );
exit(0);
}
for(;;)
{
int ret;
ret = pcap_dispatch( pt_b, 0, dev_b_handle, NULL);
if ( ret == -1 )
{
pcap_perror( pt_b, "pcap_dispatch err:");
}
}
}
void dev_b_handle( u_char *devId, const struct pcap_pkthdr *hdr, const u_char *packet )
{
//printf("%s,capture size :%d ",devId, hdr->caplen );
u_int8_t eth_a[ETH_ALEN];
u_int8_t eth_b[ETH_ALEN];
struct ether_header ehdr;
memcpy( &ehdr, packet, sizeof( struct ether_header ));
/* Only transmit source address is 221(eth2 MAC last bytes) */
if( ehdr.ether_shost[ETH_ALEN-1] == 221 )
{
printf("B src:%d, dst:%d ", ehdr.ether_shost[ETH_ALEN-1], ehdr.ether_dhost[ETH_ALEN-1] );
int c;
c = libnet_write_link( net_b, (u_char*)packet, hdr->caplen );
//printf("B write: %d ", c );
}
}