Kelvin's Colorworld
9四/120

perl调用shell

perl调用shell有三种方法:system,``,和exec

区别是system不会有返回值,``可以有返回值,exec执行完则return。

因此如果在循环中调用一些复杂的shell指令,例如strace,最好使用system,否则perl会等待返回值导致perl无法执行下去。

22十二/110

2011冬至

都说冬大过年,就是冬至比新年还要重要。但说归说,春节始终是中国人的第一节日,连民俗说法都那么言不其实,真是服了中国两面三刀城大府深的优良传统。
罢了,今天加了会儿班,晚上吃了白切鸡,还有久违的库存发菜,总算又过了个冬至。
Lami也两个月零一天大了呢。

Posted from WordPress for Windows Phone

22十二/110

Test

Post from my wp7.

Posted from WordPress for Windows Phone

13十二/110

基于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, &ethernet_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

13十二/110

用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;
}

11十二/110

用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");

11十二/110

用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");
        }
}

30十一/110

(转)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

17十一/110

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果然坑爹~

15十一/110

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下编译通过。

第 1 页,共 60 页12345...102030...最旧 »