perl调用shell
perl调用shell有三种方法:system,``,和exec
区别是system不会有返回值,``可以有返回值,exec执行完则return。
因此如果在循环中调用一些复杂的shell指令,例如strace,最好使用system,否则perl会等待返回值导致perl无法执行下去。
2011冬至
都说冬大过年,就是冬至比新年还要重要。但说归说,春节始终是中国人的第一节日,连民俗说法都那么言不其实,真是服了中国两面三刀城大府深的优良传统。
罢了,今天加了会儿班,晚上吃了白切鸡,还有久违的库存发菜,总算又过了个冬至。
Lami也两个月零一天大了呢。
Posted from WordPress for Windows Phone
基于libpcap的ARP欺骗工具
做这个工具的目的不是为了搞破坏,只是为了做防火墙测试。
由于需要模拟生产数据包,因此需要自己动手写ARP欺骗程序来回应防火墙的ARP询问。
这个程序会一直监听某个网卡,一收到ARP询问就通过rawsocket构造一个ARP回应包发送出去。
本程序有两个部分,一个是收包,基于libpcap;另一个是发包,不依赖任何第三方类库,直接通过rawsocket从链路层开始构造ARP包发出去。
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
#pragma pack(1)
unsigned char p_src_addr[15]; //src_ip buffer
unsigned char p_dst_addr[15]; //dst_ip buffer
unsigned char p_dst_mac[17]; //dst_mac buffer
unsigned char* p_src_mac = "AA:BB:CC:DD:EE:FF"; //defined mac
unsigned char* p_interface; //interface pointer
unsigned char buffer[8192]; //rawsocket data buffer
int s = -1; //socket handler
struct sockaddr_ll sa;
int offset = 0; //rawsocket data offset
u_int16_t handle_ethernet(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packet)
{
struct ether_header *eptr; /* net/ethernet.h */
eptr = (struct ether_header *) packet;
return ntohs(eptr->ether_type);
}
struct myarphdr
{
unsigned short hw_type; /* hardware address */
unsigned short protocol_type; /* protocol address */
unsigned char hw_addr_len; /* length of hardware address */
unsigned char protocol_addr_len; /* length of protocol address */
unsigned short opcode; /*operate code 1 ask 2 reply*/
unsigned char src_mac[6];
struct in_addr src_ip;
unsigned char dst_mac[6];
struct in_addr dst_ip;
unsigned char padding[18];
};
int setup_eth_header(unsigned char* buffer, unsigned char* src_mac, unsigned char* dst_mac)
{
char s_mac[6];
sscanf(src_mac, "%x:%x:%x:%x:%x:%x", &s_mac[0], &s_mac[1], &s_mac[2], &s_mac[3], &s_mac[4], &s_mac[5]);
char d_mac[6];
sscanf(dst_mac, "%x:%x:%x:%x:%x:%x", &d_mac[0], &d_mac[1], &d_mac[2], &d_mac[3], &d_mac[4], &d_mac[5]);
struct ethhdr ethernet_header;
memcpy(ethernet_header.h_dest, d_mac, 6);
memcpy(ethernet_header.h_source, s_mac, 6);
ethernet_header.h_proto = htons(0x0806);
memcpy(buffer, ðernet_header, sizeof(struct ethhdr));
return sizeof(struct ethhdr);
};
int setup_arp_header(unsigned char* buffer, unsigned char* src_mac, unsigned char* dst_mac, unsigned char* src_address, unsigned char* dst_address){
char s_mac[6];
sscanf(src_mac, "%x:%x:%x:%x:%x:%x", &s_mac[0], &s_mac[1], &s_mac[2], &s_mac[3], &s_mac[4], &s_mac[5]);
char d_mac[6];
sscanf(dst_mac, "%x:%x:%x:%x:%x:%x", &d_mac[0], &d_mac[1], &d_mac[2], &d_mac[3], &d_mac[4], &d_mac[5]);
struct myarphdr arp_header;
arp_header.hw_type = htons(0x0001);
arp_header.protocol_type = htons(0x0800);
arp_header.hw_addr_len = (unsigned char)6;
arp_header.protocol_addr_len = (unsigned char)4;
arp_header.opcode = htons(0x0002);
memcpy(arp_header.src_mac, s_mac, 6);
arp_header.src_ip.s_addr = inet_addr(src_address);
memcpy(arp_header.dst_mac, d_mac, 6);
arp_header.dst_ip.s_addr = inet_addr(dst_address);
memset(arp_header.padding,0 , 18);
memcpy(buffer, &arp_header, sizeof(struct myarphdr));
return sizeof(struct myarphdr);
}
u_char* handle_arp(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char* packet)
{
struct ether_header *eptr;
struct myarphdr *arp;
u_int length = pkthdr->len;
eptr = (struct ether_header*)packet;
arp = (struct myarphdr*)(packet + sizeof(struct ether_header));
length -= sizeof(struct ether_header);
if (length < sizeof(struct myarphdr))
{
printf(" return 0;
}
p_interface = argv[1];
char ebuf[PCAP_ERRBUF_SIZE];
pcap_t *pd = pcap_open_live (argv[1], BUFSIZ, 1, -1, ebuf);
pcap_loop (pd, -1, my_callback, NULL);
pcap_close (pd);
if(s > 0){
close(s);
}
return 0;
}
编译后执行:
[root@cnszxxxx xxxx]# gcc -o arp_trick arp_trick.c -lpcap
执行效果如下:
[root@cnszxxxx xxxx]# ./arp_trick eth0 [ARP]inter:eth0 src_mac:AA:BB:CC:DD:EE:FF dsc_mac:0:50:56:83:46:c9 src_ip:10.11.77.200 dst_ip:10.11.77.60 somebody has replied!src_mac:0:50:56:83:35:85 dst_mac:0:1d:9:9:bd:53 [ARP]inter:eth0 src_mac:AA:BB:CC:DD:EE:FF dsc_mac:0:50:56:83:52:29 src_ip:10.11.77.200 dst_ip:10.11.77.79 somebody has replied!src_mac:0:50:56:83:35:85 dst_mac:0:50:56:83:2b:cd [ARP]inter:eth0 src_mac:AA:BB:CC:DD:EE:FF dsc_mac:0:f:1f:69:7b:fa src_ip:10.11.77.43 dst_ip:10.11.77.108 [ARP]inter:eth0 src_mac:AA:BB:CC:DD:EE:FF dsc_mac:0:f:1f:69:7b:fa src_ip:10.11.77.56 dst_ip:10.11.77.108 [ARP]inter:eth0 src_mac:AA:BB:CC:DD:EE:FF dsc_mac:0:50:56:83:16:1c src_ip:10.11.77.40 dst_ip:10.11.77.41 somebody has replied!src_mac:0:50:56:83:35:85 dst_mac:0:50:56:83:16:1c [ARP]inter:eth0 src_mac:AA:BB:CC:DD:EE:FF dsc_mac:0:1d:9:9:bd:53 src_ip:10.11.77.61 dst_ip:10.11.77.62 [ARP]inter:eth0 src_mac:AA:BB:CC:DD:EE:FF dsc_mac:0:1d:9:9:bd:53 src_ip:10.11.77.40 dst_ip:10.11.77.62 somebody has replied!src_mac:0:50:56:83:35:85 dst_mac:0:1d:9:9:bd:53
用C语言解析cap文件β
具体的分析看这里:http://www.falaosao.net/?p=1268
这个版本增加了对sniffer格式cap文件的支持,同时兼容tcpdump和wireshark产生的cap文件。无非就是根据文件头判断文件格式,然后修改偏移位置,代码很简单,就不再解释了。
#include <stdio.h>
#include <stdlib.h>
unsigned const char sniffer_header[12] = {0x58,0x43,0x50,0x00,0x30,0x30,0x32,0x2E,0x30,0x30,0x32,0x00};
unsigned const char tcpdump_header[12] = {0xD4,0xC3,0xB2,0xA1,0x02,0x00,0x04,0x00,0x00,0x00,0x00,0x00};
int OFFSET_IP;
int OFFSET_MAC;
int OFFSET;
int PADDING;
int S_PACKLEN_SIZE;
int PACK_LEN;
struct FileHeader{
char flag[12];
};
struct EthHeader {
unsigned char MacDst[6];
unsigned char MacSrc[6];
unsigned short ProtocolType;
};
struct PackLength_sniffer {
unsigned short len;
};
struct PackLength_tcpdump {
int len;
};
struct IPHeader {
unsigned int IpSrc;
unsigned int IpDst;
unsigned short PortSrc;
unsigned short PortDst;
int seq_num;
};
int main(int argc, char *argv[]){
if(argc < 2){
printf("usaged:%s filename\n", argv[0]);
return 0;
}
char *filename = argv[1];
struct EthHeader ether_header;
void* p_pack_len;
struct IPHeader p_ip_struct;
struct FileHeader file_header;
FILE *fp = NULL;
fp = fopen(filename, "rb");
fread(&file_header, sizeof(file_header), 1, fp);
int c1,c2;
c1 = strcmp(tcpdump_header, file_header.flag);
c2 = strcmp(sniffer_header, file_header.flag);
if(c1 == 0){
OFFSET = 32;
OFFSET_IP = 34;
PADDING = 8;
S_PACKLEN_SIZE = sizeof(struct PackLength_tcpdump);
struct PackLength_tcpdump * p_tmp;
p_tmp = malloc(sizeof(struct PackLength_tcpdump));
p_pack_len = p_tmp;
}else if(c2 == 0){
OFFSET = 136;
OFFSET_IP = 58;
PADDING = 36;
S_PACKLEN_SIZE = sizeof(struct PackLength_sniffer);
struct PackLength_sniffer * p_tmp;
p_tmp = malloc(sizeof(struct PackLength_sniffer));
p_pack_len = p_tmp;
}else{
printf("unknow file!\n");
return 0;
}
fseek(fp, 0, SEEK_END);
int fileLen = ftell(fp);
while(OFFSET + S_PACKLEN_SIZE <= fileLen){
fseek(fp, OFFSET, 0);
fread(p_pack_len, S_PACKLEN_SIZE, 1, fp);
if(c1 == 0)
PACK_LEN = ((struct PackLength_tcpdump *)p_pack_len)->len;
else if(c2 == 0)
PACK_LEN = ((struct PackLength_sniffer *)p_pack_len)->len;
fseek(fp, OFFSET + OFFSET_IP ,0);
fread(&p_ip_struct, sizeof(struct IPHeader), 1, fp);
unsigned int mask = 0x000000ff;
int i;
unsigned int val;
for(i = 0; i < 4; i++){
val = p_ip_struct.IpSrc & mask;
val = (val >> 8 * i );
printf("%u", val);
mask = mask << 8;
if(i < 3)
printf(".");
}
printf(":%u", ntohs(p_ip_struct.PortSrc)); printf("->");
mask = 0x000000ff;
for(i = 0; i < 4; i++){
val = p_ip_struct.IpDst & mask;
val = (val >> 8 * i );
printf("%u", val);
mask = mask << 8;
if(i < 3) printf(".");
}
printf(":%u ", ntohs(p_ip_struct.PortDst));
printf(" %d\n",ntohl(p_ip_struct.seq_num));
OFFSET += PACK_LEN + S_PACKLEN_SIZE * 2 + PADDING;
}
fclose(fp);
return 0;
}
用perl转换掩码格式
很简单的Perl程序,用于转换掩码格式,从IP转换为数字或从数字转换为IP,但对于IP没有做验证,只是判断小于128.0.0.0以下就die。
#!/usr/bin/perl
use strict;
sub int_to_addr{
my $mask_int = $_[0];
my $fullmask = 0xffffffff;
my $truemask = $fullmask << (32 - 24);
my $ip1 = $truemask >> 24;
my $ip2 = ($truemask - ($ip1 << 24)) >> 16;
my $ip3 = ($truemask - ($ip1 << 24) - ($ip2 << 16)) >> 8;
my $ip4 = $truemask - ($ip1 << 24) - ($ip2 << 16) - ($ip3 << 8);
print("$ip1.$ip2.$ip3.$ip4\n");
}
sub addr_to_int{
my $mask_addr = $_[0];
my @ips = split(/\./, $mask_addr);
my $ip1 = $ips[0];
if($ip1 < 128) {
die ("invalid mask!");
return;
}
my $ip2 = $ips[1];
my $ip3 = $ips[2];
my $ip4 = $ips[3];
my $mask_int = ((0xff - $ip1) << 24) + ((0xff - $ip2) << 16) + ((0xff - $ip3) <<8) + (0xff - $ip4);
my $i = 1;
while($mask_int >> $i){
$i ++;
}
print((32 - $i)."\n");
}
int_to_addr(24);
addr_to_int("255.255.255.0");
用perl根据子网掩码列出所有IP
小程序,记录一下,下次懒得重新写了。
#!/usr/bin/perl
use strict;
show_ip("11.22.33.44", 24); # ip, mask
sub show_ip{
my $ip = $_[0];
my $mask = $_[1];
my @ips = split(/\./, $ip);
my $ip1 = @ips[0];
my $ip2 = @ips[1];
my $ip3 = @ips[2];
my $ip4 = @ips[3];
my $fullmask = 0xffffffff;
my $truemask = $fullmask << (32 - $mask);
my $ip_int = ($ip1 << 24) + ($ip2 << 16) + ($ip3 <<8) + $ip4;
my $ip_int_net = $ip_int & $truemask;
for(my $i = 0; $i < 2 ** (32 - $mask); $i++){
my $ip_int_new = $ip_int_net + $i;
$ip1 = $ip_int_new >> 24;
$ip2 = ($ip_int_new - ($ip1 << 24)) >> 16;
$ip3 = ($ip_int_new - ($ip1 << 24) - ($ip2 << 16)) >> 8;
$ip4 = ($ip_int_new - ($ip1 << 24) - ($ip2 << 16) - ($ip3 <<8));
print("$ip1.$ip2.$ip3.$ip4\n");
}
}
(转)ip包checksum算法
这篇文章很不错,把一头雾水的checksum讲得很清楚,转下来保存。
在发送数据时,为了计算数IP据报的校验和。应该按如下步骤:
(1) 把IP数据报的校验和字段置为0。
(2) 把首部看成以16位为单位的数字组成,依次进行二进制反码求和。
(3) 把得到的结果存入校验和字段中。
在接收数据时,计算数据报的校验和相对简单,按如下步骤:
(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。
(2)检查计算出的校验和的结果是否等于零。
(3)如果等于零,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。
Linux 2.6内核中的校验算法,使用汇编语言编写的,显然效率要高些
/usr/src/linux-2.6.23/include/asm-i386/checksum.h
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
unsigned int sum;
__asm__ __volatile__(
"movl (%1), %0 -;\n"
"subl $4, %2 -;\n"
"jbe 2f ;\n"
"addl 4(%1), %0 ;\n"
"adcl 8(%1), %0 ;\n"
"adcl 12(%1),%0 ;\n"
"1: adcl 16(%1), %0 ;\n"
"lea 4(%1), %1 -;\n"
"decl %2 ;\n"
"jne 1b -;\n"
"adcl $0, %0 ;\n"
"movl %0, %2 ;\n"
"shrl $16, %0 ;\n"
"addw %w2, %w0 -;\n"
"adcl $0, %0 ;\n"
"notl %0 ;\n"
"2: ;\n"
: "=r" (sum), "=r" (iph), "=r" (ihl)
: "1" (iph), "2" (ihl)
: "memory");
return (__force __sum16)sum;
}
(1) 将IP头部(包括可选项)以32位为单位进行进位加法运算
(2) 将sum的低16位和高16位相加
(3) 取反
1b -- 1 before
在这个函数中,第一个参数显然就是IP数据报的首地址,所有算法几乎一样。需要注意的是第二个参数,它是直接使用IP数据报头信息中的首部长度字段,不需要进行转换,因此,速度又快了(高手就是考虑的周到)
第二种算法就非常普通了,是用C语言编写的。许多实现网络协议栈的代码,这个算法是最常用的了,即使变化,也无非是先取反后取和之类的。考虑其原因,估计还是C语言的移植性更好吧。下面是该函数的实现:
unsigned short checksum(unsigned short *buf, int nword)
{
unsigned long sum;
for(sum = 0; nword > 0; nword--)
sum += *buf++;
sum = (sum>>16) + (sum&0xffff);
sum += (sum>>16);
return ~sum;
}
让我们假设一个IP头数据,来解cksum的惑
IP头数据:
01000101 /*ver_hlen*/
00000000 /*tos*/
00000000 00000010 /*len*/
00000000 00000000 /*id*/
00000000 00000000 /*offset*/
00000100 /*ttl*/
00010001 /*type*/
00000000 00000000 /*cksum(0)*/
01111111 00000000 00000000 00000001 -/*sip*/
01111111 00000000 00000000 00000001 -/*dip*/
运算过程(注意是大端格式加):
for(sum = 0; nword > 0; nword--)
sum += *buf++;
-01000101 00000000
-00000000 00000010
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000100 00010001
---------------------
-01001001 00010011
-00000000 00000000
---------------------
-01001001 00010011
-01111111 00000000
---------------------
-11001000 00010011
-00000000 00000001
---------------------
-11001000 00010100
-01111111 00000000
---------------------
101000111 00010100
-00000000 00000001
---------------------
101000111 00010101 sum
sum = (sum>>16) + (sum&0xffff);
00000000 00000001 (sum>>16)
01000111 00010101 (sum&0xffff)
---------------------
01000111 00010110
sum += (sum>>16);
01000111 00010110
00000000 00000000 (sum>>16)
---------------------
01000111 00010110 sum
~sum
10111000 11101001 cksum
说白了就是循环加,然后在取反!
对方机器调用checksum()计算校验和,如果校验和为0表明IP包传输正确
-----------------------------------------------------------
01000101 /*ver_hlen*/
00000000 /*tos*/
00000000 00000010 /*len*/
00000000 00000000 /*id*/
00000000 00000000 /*offset*/
00000100 /*ttl*/
00010001 /*type*/
10111000 11101001 /*cksum(0)*/
01111111 00000000 00000000 00000001 /*sip*/
01111111 00000000 00000000 00000001 /*dip*/
-01000101 00000000
-00000000 00000010
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000000 00000000
---------------------
-01000101 00000010
-00000100 00010001
---------------------
-01001001 00010011
-10111000 11101001
---------------------
100000001 11111100
-01111111 00000000
---------------------
110000000 11111100
-00000000 00000001
---------------------
110000000 11111101
-01111111 00000000
---------------------
111111111 11111101
-00000000 00000001
---------------------
111111111 11111110 sum
sum = (sum>>16) + (sum&0xffff);
00000000 00000001 (sum>>16)
11111111 11111110 (sum&0xffff)
----------------------
11111111 11111111
sum += (sum>>16);
11111111 11111111
00000000 00000000 (sum>>16)
----------------------
11111111 11111111
~sum
00000000 00000000
varnish-3.0.6安装问题
在configure源代码的时候,报出以下错误:
checking for getaddrinfo in -lnsl... yes checking for cos in -lm... yes checking for pkg-config... /usr/bin/pkg-config checking pkg-config is at least version 0.9.0... yes checking for PCRE... no configure: error: Package requirements (libpcre) were not met: No package 'libpcre' found Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables PCRE_CFLAGS and PCRE_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.
但明明装了pcre的了,怎么checking for PCRE时还是返回No呢?
baidu了半天,答案都是千篇一律配置PKG_CONFIG_PATH环境变量,试了半天都不行。
再仔细看看报错,如果不配置PKG_CONFIG_PATH环境变量,可以直接配置PCRE_CFLAGS和PCRE_LIBS这两个环境变量。
于是直接export PCRE_CFLAGS=`pcre-config --cflags`和export PCRE_LIBS=`pcre-config --libs`
再configure,通过!
再次证明,baidu果然坑爹~
Linux主动发送cdp packet
基于之前在aix上写的代码:http://www.falaosao.net/?p=1309,略作修改编译出Linux下的版本。
主要修改:
sx_write_short和sx_write_long这两个函数从适应big-endian修改为适应little-endian。
直接使用sendto,无需bind和connect,获取mac地址的函数getaddr也去掉了。
详细代码如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
static char *use_sysname = 0, *use_machine = 0;
static struct utsname myuname;
/* the capability masks */
static int cdp_capset;
#define CDP_CAP_L3R 0x01 /* a layer 3 router */
#define CDP_CAP_L2TB 0x02 /* a layer 2 transparent bridge */
#define CDP_CAP_L2SRB 0x04 /* a layer 2 source-route bridge */
#define CDP_CAP_L2SW 0x08 /* a layer 2 switch (non-spanning tree) */
#define CDP_CAP_L3TXRX 0x10 /* a layer 3 (non routing) host */
#define CDP_CAP_IGRP 0x20 /* does not forward IGMP Packets to non-routers */
#define CDP_CAP_L1 0x40 /* a layer 1 repeater */
#define LIBNET_CKSUM_CARRY(x) \
(x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff))
typedef unsigned char u_int8_t;
typedef unsigned short u_int16_t;
typedef unsigned int u_int32_t;
struct cdp_header {
/* ethernet 802.3 header */
unsigned char dst_addr[6] __attribute__ ((packed));
unsigned char src_addr[6] __attribute__ ((packed));
u_int16_t length __attribute__ ((packed));
/* LLC */
u_int8_t dsap __attribute__ ((packed));
u_int8_t ssap __attribute__ ((packed));
/* llc control */
u_int8_t control __attribute__ ((packed));
u_int8_t orgcode[3] __attribute__ ((packed));
u_int16_t protocolId __attribute__ ((packed));
};
int sx_write_short(unsigned char* buffer, u_int16_t data)
{
buffer[1]=(data>>8)&0xff;
buffer[0]=data&0xff;
return 1;
};
int sx_write_long(unsigned char* buffer, u_int32_t data)
{
buffer[3]=(data>>24)&0xff;
buffer[2]=(data>>16)&0xff;
buffer[1]=(data>>8)&0xff;
buffer[0]=data&0xff;
return 1;
};
u_int16_t libnet_ip_check(u_int16_t *addr, int len){
int sum;
sum = libnet_in_cksum(addr, len);
return (LIBNET_CKSUM_CARRY(sum));
}
int libnet_in_cksum(u_int16_t *addr, int len)
{
int sum;
#if 0
u_int16_t last_byte;
sum = 0;
last_byte = 0;
#else
union
{
u_int16_t s;
u_int8_t b[2];
}pad;
sum = 0;
#endif
while (len > 1)
{
sum += *addr++;
len -= 2;
}
#if 0
if (len == 1)
{
*(u_int8_t *)&last_byte = *(u_int8_t *)addr;
sum += last_byte;
#else
if (len == 1)
{
pad.b[0] = *(u_int8_t *)addr;
pad.b[1] = 0;
sum += pad.s;
#endif
}
return (sum);
}
int cdp_buffer_init(unsigned char* buffer, int len, unsigned char* srcaddr)
{
memset(buffer,0,len);
buffer[0]=0x01;
buffer[1]=0x00;
buffer[2]=0x0c;
buffer[3]=buffer[4]=buffer[5]=0xcc;
memcpy(buffer+6,srcaddr,6);
((struct cdp_header*)buffer)->dsap=0xaa;
((struct cdp_header*)buffer)->ssap=0xaa;
((struct cdp_header*)buffer)->control=0x03;
((struct cdp_header*)buffer)->orgcode[2]=0x0c;
sx_write_short((unsigned char*)&(((struct cdp_header*)buffer)->protocolId),
htons(0x2000));
buffer+=sizeof(struct cdp_header);
buffer[0]=0x2; /* cdp version */
buffer[1]=0xb4; /* cdp holdtime, 180 sec by default */
buffer[2]=buffer[3]=0; /* checksum - will calculate later */
return 4+sizeof(struct cdp_header);
};
static char *use_hostname = 0;
int cdp_add_device_id(unsigned char* buffer, int len)
{
static char s_hostname[256];
if (!use_hostname) {
gethostname(s_hostname,sizeof(s_hostname)-1);
s_hostname[sizeof(s_hostname)-1] = 0;
use_hostname = s_hostname;
}
if((strlen(use_hostname)+4)>len) return 0;
*(u_int16_t*)buffer=htons(0x0001); /* type=deviceId */
*((u_int16_t*)(buffer+2))=htons(strlen(use_hostname)+4); /* total length */
memcpy(buffer+4,use_hostname,strlen(use_hostname));
return strlen(use_hostname)+4;
};
int cdp_add_interface(unsigned char* buffer, int len, char* interface)
{
if(!interface) return 0;
if(len < (strlen(interface) + 4)) return 0;
sx_write_short(buffer, htons(0x0003)); /*type=PortID */
sx_write_short(buffer + 2, htons(strlen(interface) + 4)); /* totallength*/
memcpy(buffer + 4, interface, strlen(interface));
return strlen(interface) + 4;
};
int cdp_add_capabilities(unsigned char* buffer, int len)
{
if(len<8) return 0; sx_write_short(buffer,htons(0x0004)); /* type=Capabilities */ sx_write_short(buffer+2,htons(8)); /* totallength*/ sx_write_long(buffer+4,htonl(cdp_capset)); return 8; }; int cdp_add_software_version(unsigned char* buffer, int len) { if((strlen(use_sysname)+4)>len) return 0;
sx_write_short(buffer,htons(0x0005)); /* type=software version */
sx_write_short(buffer+2,htons(strlen(use_sysname)+4)); /* totallength*/
memcpy(buffer+4,use_sysname,strlen(use_sysname));
return strlen(use_sysname)+4;
};
int cdp_add_platform(unsigned char* buffer, int len)
{
if((strlen(use_machine)+4)>len) return 0;
sx_write_short(buffer,htons(0x0006)); /* type=platform */
sx_write_short(buffer+2,htons(strlen(use_machine)+4)); /* totallength*/
memcpy(buffer+4,use_machine,strlen(use_machine));
return strlen(use_machine)+4;
};
unsigned short cdp_checksum(unsigned char *ptr, int length) {
if (length % 2 == 0) {
return libnet_ip_check((u_short *)ptr, length);
} else {
int c = ptr[length-1];
unsigned short *sp = (unsigned short *)(&ptr[length-1]);
unsigned short ret;
*sp = htons(c);
ret = libnet_ip_check((u_short *)ptr, length+1);
ptr[length-1] = c;
return ret;
}
}
main(int argc, char *argv[]) {
char srcaddr[6];
char *device, dstaddr[6];
u_int ethertype;
u_int count, size;
int s;
int specify_duplex = 0;
int didcap = 0;
if (!didcap) cdp_capset = CDP_CAP_L3TXRX;
uname(&myuname);
if (!use_machine) {
use_machine = myuname.machine;
if (!use_machine) {
use_machine = "(null)";
}
}
if (!use_sysname) {
char *qa, *qb;
int buflen;
qa = myuname.sysname; if (!qa) qa = "(null)";
qb = myuname.release; if (!qb) qb = "(null)";
buflen = strlen(qa) + strlen(qb) + 2;
use_sysname = (char *)malloc(buflen);
if (!use_sysname) {
perror("malloc");
exit(1);
}
sprintf(use_sysname, "%s %s", qa, qb);
use_sysname[buflen-1] = '\0'; /* terminate if truncated */
}
if (argc != 3) {
printf("Usage: %s count\n",
argv[0]);
printf("EG: %s en0 1\n",
argv[0]);
exit(1);
}
device = argv[1];
count = atoi(argv[2]);
printf("interface: %s\n", device);
printf("count: %d\n", count);
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) {
perror("socket");
exit(1);
}
static unsigned char buffer[65535];
int offset = 0;
offset = cdp_buffer_init(buffer, sizeof(buffer), srcaddr);
offset += cdp_add_device_id(buffer + offset, sizeof(buffer) - offset);
offset += cdp_add_interface(buffer + offset, sizeof(buffer) - offset, device);
offset += cdp_add_capabilities(buffer + offset, sizeof(buffer) - offset);
offset += cdp_add_software_version(buffer + offset, sizeof(buffer) - offset);
offset += cdp_add_platform(buffer + offset, sizeof(buffer) - offset);
((struct cdp_header*)buffer) -> length = htons(offset - 14);
*(u_short*)(buffer + sizeof(struct cdp_header) + 2) = cdp_checksum(
buffer + sizeof(struct cdp_header),
offset - sizeof(struct cdp_header));
struct sockaddr_ll sa;
sa.sll_ifindex = if_nametoindex(argv[1]);
while (count-- > 0) {
if( sendto(s, buffer, offset, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0 ){
perror("send error\n");
exit(4);
}
}
}
同样在gcc下编译通过。