动机是我屋里有两台电脑,但到屋里只有一根外出网线,一台机子有双网卡,我就正好运用我前段学习的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 );
}
}