libpcap编程实例
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pcap.h> 4 #include <errno.h> 5 #include <sys/socket.h> 6 #include <netinet/in.h> 7 #include <arpa/inet.h> 8 9 int main(int argc, char **argv) 10 { 11 char *dev; 12 char *net; 13 char *mask; 14 int ret; 15 char errbuf[PCAP_ERRBUF_SIZE]; 16 bpf_u_int32 netp; 17 bpf_u_int32 maskp; 18 struct in_addr addr; 19 20 21 dev = pcap_lookupdev(errbuf); 22 23 24 if(dev == NULL) 25 { 26 printf("%s\n",errbuf); 27 exit(1); 28 } 29 30 31 printf("DEV: %s\n",dev); 32 33 34 ret = pcap_lookupnet(dev,&netp,&maskp,errbuf); 35 36 if(ret == -1) 37 { 38 printf("%s\n",errbuf); 39 exit(1); 40 } 41 42 43 addr.s_addr = netp; 44 net = inet_ntoa(addr); 45 46 if(net == NULL) 47 { 48 perror("inet_ntoa"); 49 exit(1); 50 } 51 52 printf("NET: %s\n",net); 53 54 55 addr.s_addr = maskp; 56 mask = inet_ntoa(addr); 57 58 if(mask == NULL) 59 { 60 perror("inet_ntoa"); 61 exit(1); 62 } 63 64 printf("MASK: %s\n",mask); 65 66 return 0; 67 } 68 然后gcc -o pcap_1 pcap_1.c -lpcap(一定要-lpcap参数) 69 编译ok~,执行./pcap_1,可以看到: 70 DEV: eth0 71 NET: 192.168.12.0 72 MASK: 255.255.255.0 73 好了,第一个pcap程序出炉了。。。。。 74 75 但是(当然有但是了,要不然我后面写啥),上面那个程序除了向我们展现pcap_lookupdev和pcap_lookupnet之外什么都没有干,好,我们接着来,动手编写我们的第一个抓包程序。 76 77 #include <stdio.h> 78 #include <stdlib.h> 79 #include <pcap.h> 80 #include <errno.h> 81 #include <sys/socket.h> 82 #include <netinet/in.h> 83 #include <arpa/inet.h> 84 #include <netinet/if_ether.h> 85 86 int main(int argc, char **argv) 87 { 88 int i; 89 char *dev; 90 char errbuf[PCAP_ERRBUF_SIZE]; 91 pcap_t* descr; 92 const u_char *packet; 93 struct pcap_pkthdr hdr; 94 struct ether_header *eptr; 95 96 u_char *ptr; 97 98 99 dev = pcap_lookupdev(errbuf); 100 101 if(dev == NULL) 102 { 103 printf("%s\n",errbuf); 104 exit(1); 105 } 106 107 printf("DEV: %s\n",dev); 108 109 110 111 descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf); 112 113 if(descr == NULL) 114 { 115 printf("pcap_open_live(): %s\n",errbuf); 116 exit(1); 117 } 118 119 120 121 122 packet = pcap_next(descr,&hdr); 123 124 if(packet == NULL) 125 { 126 printf("Didn't grab packet\n"); 127 exit(1); 128 } 129 130 131 132 printf("Grabbed packet of length %d\n",hdr.len); 133 printf("Recieved at ..... %s\n",ctime((const time_t*)&hdr.ts.tv_sec)); 134 printf("Ethernet address length is %d\n",ETHER_HDR_LEN); 135 136 137 eptr = (struct ether_header *) packet; 138 139 140 if (ntohs (eptr->ether_type) == ETHERTYPE_IP) 141 { 142 printf("Ethernet type hex:%x dec:%d is an IP packet\n", 143 ntohs(eptr->ether_type), 144 ntohs(eptr->ether_type)); 145 }else if (ntohs (eptr->ether_type) == ETHERTYPE_ARP) 146 { 147 printf("Ethernet type hex:%x dec:%d is an ARP packet\n", 148 ntohs(eptr->ether_type), 149 ntohs(eptr->ether_type)); 150 }else { 151 printf("Ethernet type %x not IP", ntohs(eptr->ether_type)); 152 exit(1); 153 } 154 155 156 ptr = eptr->ether_dhost; 157 i = ETHER_ADDR_LEN; 158 printf(" Destination Address: "); 159 do{ 160 printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++); 161 }while(--i>0); 162 printf("\n"); 163 164 ptr = eptr->ether_shost; 165 i = ETHER_ADDR_LEN; 166 printf(" Source Address: "); 167 do{ 168 printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++); 169 }while(--i>0); 170 printf("\n"); 171 172 return 0; 173 } 174 175 好了,编译运行! 176 [root@norman libpcap]# ./pcap_2 177 DEV: eth0 178 Grabbed packet of length 76 179 Recieved at time..... Mon Mar 12 22:23:29 2001 180 181 Ethernet address length is 14 182 Ethernet type hex:800 dec:2048 is an IP packet 183 Destination Address: 0:20:78:d1:e8:1 184 Source Address: 0:a0:cc:56:c2:91 185 [root@pepe libpcap]# 186 187 可能有人等了半天都没有一个包过来,有个好办法,再开一个控制台,ping一下某个网站,比如google~~,呵呵 188 马上就有反应了~~ 189 190 这个程序是一个老外写的,大家看看注释应该没有问题吧~ 191 但是大家也发现了一个问题,就是上面的程序只能捕捉一个包,要不停的捕捉包怎么办,用循环??libpcap提供了一个更好的方法: 192 int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user); 193 这个函数能够不停的捕捉以太网的包,cnt就是捕捉的次数,callback是处理函数,这个处理函数怎么写,看看pcap_3.c就知道了。user参数是干什么的?不要问我,我也不知道。 194 195 #include <pcap.h> 196 #include <stdio.h> 197 #include <stdlib.h> 198 #include <errno.h> 199 #include <sys/socket.h> 200 #include <netinet/in.h> 201 #include <arpa/inet.h> 202 #include <netinet/if_ether.h> 203 204 205 void my_callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* 206 packet) 207 { 208 static int count = 1; 209 fprintf(stdout,"%d, ",count); 210 if(count == 4) 211 fprintf(stdout,"Come on baby sayyy you love me!!! "); 212 if(count == 7) 213 fprintf(stdout,"Tiiimmmeesss!! "); 214 fflush(stdout); 215 count++; 216 } 217 218 int main(int argc,char **argv) 219 { 220 int i; 221 char *dev; 222 char errbuf[PCAP_ERRBUF_SIZE]; 223 pcap_t* descr; 224 const u_char *packet; 225 struct pcap_pkthdr hdr; 226 struct ether_header *eptr; 227 228 if(argc != 2){ fprintf(stdout,"Usage: %s numpackets\n",argv[0]);return 0;} 229 230 231 dev = pcap_lookupdev(errbuf); 232 if(dev == NULL) 233 { printf("%s\n",errbuf); exit(1); } 234 235 descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf); 236 if(descr == NULL) 237 { printf("pcap_open_live(): %s\n",errbuf); exit(1); } 238 239 240 241 pcap_loop(descr,atoi(argv[1]),my_callback,NULL); 242 243 fprintf(stdout,"\nDone processing packets... wheew!\n"); 244 return 0; 245 } 246 247 运行./pcap_3 7 248 1, 2, 3, 4, Come on baby sayyy you love me!!! 5, 6, 7, Tiiimmmeesss!! 249 Done processing packets... wheew! 250 251 pcap_loop确实很好用,但是如果没有包包过来,只有干等在那里,pcap_dispatch就含有一个超时的功能,下面是man里面的一段话: 252 pcap_dispatch() is used to collect and process packets. cnt specifies the maximum number of packets to process before returning. A cnt of -1 processes all the packets received in one buffer. A cnt of 0 processes all packets until an error occurs, EOF is reached, or the read times out (when doing live reads and a non-zero read timeout is specified). callback specifies a routine to be called with three arguments: a u_char pointer which is passed in from pcap_dispatch(), a pointer to the pcap_pkthdr struct (which precede the actual network headers and data), and a u_char pointer to the packet data. The number of packets read is returned. Zero is returned when EOF is reached in a ``savefile.'' A return of -1 indicates an error in which case pcap_perror() or pcap_geterr() may be used to display the error text. 253 254 另外的问题是,我们可能对抓取的包包太多而很头痛,可能很多都不是我们感兴趣的包,别急,pcap_compile和pcap_setfilter能帮我们解决问题。 255 256 #include <pcap.h> 257 #include <stdio.h> 258 #include <stdlib.h> 259 #include <errno.h> 260 #include <sys/socket.h> 261 #include <netinet/in.h> 262 #include <arpa/inet.h> 263 #include <netinet/if_ether.h> 264 265 266 void my_callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* 267 packet) 268 { 269 static int count = 1; 270 fprintf(stdout,"%d, ",count); 271 fflush(stdout); 272 count++; 273 } 274 275 int main(int argc,char **argv) 276 { 277 int i; 278 char *dev; 279 char errbuf[PCAP_ERRBUF_SIZE]; 280 pcap_t* descr; 281 const u_char *packet; 282 struct pcap_pkthdr hdr; 283 struct ether_header *eptr; 284 struct bpf_program fp; 285 bpf_u_int32 maskp; 286 bpf_u_int32 netp; 287 288 289 if(argc != 2){ fprintf(stdout,"Usage: %s \"filter program\"\n" 290 ,argv[0]);return 0;} 291 292 293 dev = pcap_lookupdev(errbuf); 294 if(dev == NULL) 295 { fprintf(stderr,"%s\n",errbuf); exit(1); } 296 297 298 pcap_lookupnet(dev,&netp,&maskp,errbuf); 299 300 301 descr = pcap_open_live(dev,BUFSIZ,1,-1,errbuf); 302 if(descr == NULL) 303 { printf("pcap_open_live(): %s\n",errbuf); exit(1); } 304 305 306 if(pcap_compile(descr,&fp,argv[1],0,netp) == -1) 307 { fprintf(stderr,"Error calling pcap_compile\n"); exit(1); } 308 309 310 if(pcap_setfilter(descr,&fp) == -1) 311 { fprintf(stderr,"Error setting filter\n"); exit(1); } 312 313 314 pcap_loop(descr,-1,my_callback,NULL); 315 316 return 0; 317 } 318 319 运行./pcap_4.c "host www.google.com" 320 然后在另外一个控制台下面ping www.baidu.com 321 哈哈 322 没有反应吧 323 接着再ping www.google.com 324 就看到1, 2, 3, 4, 5, 6, 325 ok 326 you got it!!
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pcap.h> 4 #include <errno.h> 5 #include <sys/socket.h> 6 #include <netinet/in.h> 7 #include <arpa/inet.h> 8 9 int main(int argc, char **argv) 10 { 11 char *dev; 12 char *net; 13 char *mask; 14 int ret; 15 char errbuf[PCAP_ERRBUF_SIZE]; 16 bpf_u_int32 netp; 17 bpf_u_int32 maskp; 18 struct in_addr addr; 19 20 21 dev = pcap_lookupdev(errbuf); 22 23 24 if(dev == NULL) 25 { 26 printf("%s\n",errbuf); 27 exit(1); 28 } 29 30 31 printf("DEV: %s\n",dev); 32 33 34 ret = pcap_lookupnet(dev,&netp,&maskp,errbuf); 35 36 if(ret == -1) 37 { 38 printf("%s\n",errbuf); 39 exit(1); 40 } 41 42 43 addr.s_addr = netp; 44 net = inet_ntoa(addr); 45 46 if(net == NULL) 47 { 48 perror("inet_ntoa"); 49 exit(1); 50 } 51 52 printf("NET: %s\n",net); 53 54 55 addr.s_addr = maskp; 56 mask = inet_ntoa(addr); 57 58 if(mask == NULL) 59 { 60 perror("inet_ntoa"); 61 exit(1); 62 } 63 64 printf("MASK: %s\n",mask); 65 66 return 0; 67 } 68 然后gcc -o pcap_1 pcap_1.c -lpcap(一定要-lpcap参数) 69 编译ok~,执行./pcap_1,可以看到: 70 DEV: eth0 71 NET: 192.168.12.0 72 MASK: 255.255.255.0 73 好了,第一个pcap程序出炉了。。。。。 74 75 但是(当然有但是了,要不然我后面写啥),上面那个程序除了向我们展现pcap_lookupdev和pcap_lookupnet之外什么都没有干,好,我们接着来,动手编写我们的第一个抓包程序。 76 77 #include <stdio.h> 78 #include <stdlib.h> 79 #include <pcap.h> 80 #include <errno.h> 81 #include <sys/socket.h> 82 #include <netinet/in.h> 83 #include <arpa/inet.h> 84 #include <netinet/if_ether.h> 85 86 int main(int argc, char **argv) 87 { 88 int i; 89 char *dev; 90 char errbuf[PCAP_ERRBUF_SIZE]; 91 pcap_t* descr; 92 const u_char *packet; 93 struct pcap_pkthdr hdr; 94 struct ether_header *eptr; 95 96 u_char *ptr; 97 98 99 dev = pcap_lookupdev(errbuf); 100 101 if(dev == NULL) 102 { 103 printf("%s\n",errbuf); 104 exit(1); 105 } 106 107 printf("DEV: %s\n",dev); 108 109 110 111 descr = pcap_open_live(dev,BUFSIZ,1,0,errbuf); 112 113 if(descr == NULL) 114 { 115 printf("pcap_open_live(): %s\n",errbuf); 116 exit(1); 117 } 118 119 120 121 122 packet = pcap_next(descr,&hdr); 123 124 if(packet == NULL) 125 { 126 printf("Didn't grab packet\n"); 127 exit(1); 128 } 129 130 131 132 printf("Grabbed packet of length %d\n",hdr.len); 133 printf("Recieved at ..... %s\n",ctime((const time_t*)&hdr.ts.tv_sec)); 134 printf("Ethernet address length is %d\n",ETHER_HDR_LEN); 135 136 137 eptr = (struct ether_header *) packet; 138 139 140 if (ntohs (eptr->ether_type) == ETHERTYPE_IP) 141 { 142 printf("Ethernet type hex:%x dec:%d is an IP packet\n", 143 ntohs(eptr->ether_type), 144 ntohs(eptr->ether_type)); 145 }else if (ntohs (eptr->ether_type) == ETHERTYPE_ARP) 146 { 147 printf("Ethernet type hex:%x dec:%d is an ARP packet\n", 148 ntohs(eptr->ether_type), 149 ntohs(eptr->ether_type)); 150 }else { 151 printf("Ethernet type %x not IP", ntohs(eptr->ether_type)); 152 exit(1); 153 } 154 155 156 ptr = eptr->ether_dhost; 157 i = ETHER_ADDR_LEN; 158 printf(" Destination Address: "); 159 do{ 160 printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++); 161 }while(--i>0); 162 printf("\n"); 163 164 ptr = eptr->ether_shost; 165 i = ETHER_ADDR_LEN; 166 printf(" Source Address: "); 167 do{ 168 printf("%s%x",(i == ETHER_ADDR_LEN) ? " " : ":",*ptr++); 169 }while(--i>0); 170 printf("\n"); 171 172 return 0; 173 } 174 175 好了,编译运行! 176 [root@norman libpcap]# ./pcap_2 177 DEV: eth0 178 Grabbed packet of length 76 179 Recieved at time..... Mon Mar 12 22:23:29 2001 180 181 Ethernet address length is 14 182 Ethernet type hex:800 dec:2048 is an IP packet 183 Destination Address: 0:20:78:d1:e8:1 184 Source Address: 0:a0:cc:56:c2:91 185 [root@pepe libpcap]# 186 187 可能有人等了半天都没有一个包过来,有个好办法,再开一个控制台,ping一下某个网站,比如google~~,呵呵 188 马上就有反应了~~ 189 190 这个程序是一个老外写的,大家看看注释应该没有问题吧~ 191 但是大家也发现了一个问题,就是上面的程序只能捕捉一个包,要不停的捕捉包怎么办,用循环??libpcap提供了一个更好的方法: 192 int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user); 193 这个函数能够不停的捕捉以太网的包,cnt就是捕捉的次数,callback是处理函数,这个处理函数怎么写,看看pcap_3.c就知道了。user参数是干什么的?不要问我,我也不知道。 194 195 #include <pcap.h> 196 #include <stdio.h> 197 #include <stdlib.h> 198 #include <errno.h> 199 #include <sys/socket.h> 200 #include <netinet/in.h> 201 #include <arpa/inet.h> 202 #include <netinet/if_ether.h> 203 204 205 void my_callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* 206 packet) 207 { 208 static int count = 1; 209 fprintf(stdout,"%d, ",count); 210 if(count == 4) 211 fprintf(stdout,"Come on baby sayyy you love me!!! "); 212 if(count == 7) 213 fprintf(stdout,"Tiiimmmeesss!! "); 214 fflush(stdout); 215 count++; 216 } 217 218 int main(int argc,char **argv) 219 { 220 int i; 221 char *dev; 222 char errbuf[PCAP_ERRBUF_SIZE]; 223 pcap_t* descr; 224 const u_char *packet; 225 struct pcap_pkthdr hdr; 226 struct ether_header *eptr; 227 228 if(argc != 2){ fprintf(stdout,"Usage: %s numpackets\n",argv[0]);return 0;} 229 230 231 dev = pcap_lookupdev(errbuf); 232 if(dev == NULL) 233 { printf("%s\n",errbuf); exit(1); } 234 235 descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf); 236 if(descr == NULL) 237 { printf("pcap_open_live(): %s\n",errbuf); exit(1); } 238 239 240 241 pcap_loop(descr,atoi(argv[1]),my_callback,NULL); 242 243 fprintf(stdout,"\nDone processing packets... wheew!\n"); 244 return 0; 245 } 246 247 运行./pcap_3 7 248 1, 2, 3, 4, Come on baby sayyy you love me!!! 5, 6, 7, Tiiimmmeesss!! 249 Done processing packets... wheew! 250 251 pcap_loop确实很好用,但是如果没有包包过来,只有干等在那里,pcap_dispatch就含有一个超时的功能,下面是man里面的一段话: 252 pcap_dispatch() is used to collect and process packets. cnt specifies the maximum number of packets to process before returning. A cnt of -1 processes all the packets received in one buffer. A cnt of 0 processes all packets until an error occurs, EOF is reached, or the read times out (when doing live reads and a non-zero read timeout is specified). callback specifies a routine to be called with three arguments: a u_char pointer which is passed in from pcap_dispatch(), a pointer to the pcap_pkthdr struct (which precede the actual network headers and data), and a u_char pointer to the packet data. The number of packets read is returned. Zero is returned when EOF is reached in a ``savefile.'' A return of -1 indicates an error in which case pcap_perror() or pcap_geterr() may be used to display the error text. 253 254 另外的问题是,我们可能对抓取的包包太多而很头痛,可能很多都不是我们感兴趣的包,别急,pcap_compile和pcap_setfilter能帮我们解决问题。 255 256 #include <pcap.h> 257 #include <stdio.h> 258 #include <stdlib.h> 259 #include <errno.h> 260 #include <sys/socket.h> 261 #include <netinet/in.h> 262 #include <arpa/inet.h> 263 #include <netinet/if_ether.h> 264 265 266 void my_callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* 267 packet) 268 { 269 static int count = 1; 270 fprintf(stdout,"%d, ",count); 271 fflush(stdout); 272 count++; 273 } 274 275 int main(int argc,char **argv) 276 { 277 int i; 278 char *dev; 279 char errbuf[PCAP_ERRBUF_SIZE]; 280 pcap_t* descr; 281 const u_char *packet; 282 struct pcap_pkthdr hdr; 283 struct ether_header *eptr; 284 struct bpf_program fp; 285 bpf_u_int32 maskp; 286 bpf_u_int32 netp; 287 288 289 if(argc != 2){ fprintf(stdout,"Usage: %s \"filter program\"\n" 290 ,argv[0]);return 0;} 291 292 293 dev = pcap_lookupdev(errbuf); 294 if(dev == NULL) 295 { fprintf(stderr,"%s\n",errbuf); exit(1); } 296 297 298 pcap_lookupnet(dev,&netp,&maskp,errbuf); 299 300 301 descr = pcap_open_live(dev,BUFSIZ,1,-1,errbuf); 302 if(descr == NULL) 303 { printf("pcap_open_live(): %s\n",errbuf); exit(1); } 304 305 306 if(pcap_compile(descr,&fp,argv[1],0,netp) == -1) 307 { fprintf(stderr,"Error calling pcap_compile\n"); exit(1); } 308 309 310 if(pcap_setfilter(descr,&fp) == -1) 311 { fprintf(stderr,"Error setting filter\n"); exit(1); } 312 313 314 pcap_loop(descr,-1,my_callback,NULL); 315 316 return 0; 317 } 318 319 运行./pcap_4.c "host www.google.com" 320 然后在另外一个控制台下面ping www.baidu.com 321 哈哈 322 没有反应吧 323 接着再ping www.google.com 324 就看到1, 2, 3, 4, 5, 6, 325 ok 326 you got it!!