#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<netinet/in.h>
#include<limits.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<ctype.h>
char request[1024 * 4];
struct response
{
char head[10240];
char body[102400];
} response;
//功能:测试字符C是否是字串的最后一个
//返回值:是=1 不是=0
//副带作用:无
int
isEnd (char *s, char c)
{
if (*(s + strlen (s) - 1) == c)
return 1;
else
return 0;
}
//功能:测试字符C是否是字串的开始一个
//返回值:是=1 不是=0
//副带作用:无
int
isStart (char *s, char c)
{
if (*(s) == c)
return 1;
else
return 0;
}
//功能:在字串s中反向查找字符c
//返回值:找到=下标 没找到=-1
//副带作用:无
int
reStrChr (char *s, char c)
{
int i = strlen (s);
if (!(*s))
return -1;
while (s[i - 1])
{
if (strchr (s + (i - 1), c))
return (i - 1);
else
i--;
}
return -1;
}
//功能:在字串s中正向查找字符c
//返回值:找到=下标 没找到=-1
//副带作用:无
int
seStrChr (char *s, char c)
{
char *p;
if (!(*s))
return -1;
if (NULL != (p = strchr (s, c)))
return p - s;
else
return -1;
}
//功能:把字串s中所有字符转为小写
//返回值:无
//副带作用:参数s会改变
void
toLowerCase (char *s)
{
while (*s)
*s = tolower (*s++);
}
//功能:从web地址字串src中分析出协议,域名,路径,文件,端口
//返回值: 分析成功=1 发生错误=0
//副带作用:指钟参数char *protocal, char *web, char *path,char *file, int *port会改变
int
analyseWebAddress (char *src, char *protocal, char *web, char *path,
char *file, int *port)
{
int i;
*port = 0;
if (!(*src))
return -1;
if (!strncmp (src, "http://", strlen ("http://")))
{
strncpy (protocal, src, strlen ("http://"));
strncpy (web, src + strlen ("http://"),
strlen (src) - strlen ("http://"));
}
else if (!strncmp (src, "https://", strlen ("https://")))
{
strncpy (protocal, src, strlen ("https://"));
strncpy (web, src + strlen ("https://"),
strlen (src) - strlen ("https://"));
}
else
{
strncpy (protocal, "http://", strlen ("http://"));
strncpy (web, src, strlen (src));
}
i = seStrChr (web, '/');
if (-1 != i)
{
strncpy (path, web + i, strlen (web) - i);
web = '/0';
i = reStrChr (path, '/');
if (-1 == i)
{
strncpy (file, path, strlen (path));
path[0] = '/0';
}
else
{
strncpy (file, path + i + 1, strlen (path) - i - 1);
file[strlen (file)] = '/0';
path = '/0';
}
}
else
{
file[0] = '/0';
path[0] = '/0';
}
i = reStrChr (web, ':');
if (-1 != i)
{
*port = atoi (web + i + 1);
web = '/0';
}
else
*port = 80;
return 0;
}
//功能:把p指向的字符串添加到全局变量request之后
//返回值: 无
//副带作用:全局变量request会改变
void
addParameterToRequest (const char *p)
{
strncat (request, p, strlen (p));
}
//功能:从全局变量response.head从分析出type指向的类型
//返回值: 无
//副带作用:分析出来的值放入参数value从返回
void
getParameterFromResponseHeader (const char *type, char *value)
{
char *p;
char *q;
int t;
p = response.head;
while (NULL != (q = (strstr (p, type))))
{
t = seStrChr (q + strlen (type), ';');
strncat (value, q + strlen (type), t + 1);
p = (q + strlen (type)) + t;
}
}
//功能:向sockfd发出请求,并获得响应
//返回值: 无
//副带作用:响应存入全局变量response
void
requestRun (int sockfd)
{
int nbytes;
int send, totalsend;
char buffer[1];
int i;
long j;
int k;
send = 0;
totalsend = 0;
nbytes = strlen (request);
while (totalsend < nbytes)
{
send = write (sockfd, request + totalsend, nbytes - totalsend);
if (send == -1)
{
printf ("send error:%s/n", strerror (errno));
exit (0);
}
totalsend += send;
printf ("%d bytes send OK!/n", totalsend);
}
i = 0;
j = 0;
k = 0;
//下面这个循环需要解释下
//用i来判断响应头结束没有,分析http协议知道(用ethereal(一个抓包工具,linux redhat os光盘自带)
//查看http请求和响应数据)
//响应头的数据是有很多type:value/r/n组成的,而响应头完了后
//在响应头和响应主体之间是用"/r/n/r/n"分隔开的,所以....
while ((nbytes = read (sockfd, buffer, 1)) == 1)
{
if (i < 4)
{
if (buffer[0] == '/r' || buffer[0] == '/n')
i++;
else
i = 0;
response.head[j] = buffer[0];
j++;
}
else
{
if (0 == k)
{
k = 1;
j = 0;
}
response.body[j] = buffer[0];
j++;
}
}
}
int
main (int argc, char *argv[])
{
int sockfd;
struct sockaddr_in server_addr;
struct hostent *host;
char protocal[16];
char web[128];
char path[512];
char file[128];
char cookie[1024 * 4];
int port;
char date[1024 * 4];
char tempDate[1024];
int i, t, j, k;
if (argc != 3)
{
fprintf (stderr, "Usage:%s need two Parameter!/a/n", argv[0]);
exit (1);
}
//初始,全部置‘/0’
memset (request, '/0', sizeof (request));
memset (protocal, '/0', sizeof (protocal));
memset (web, '/0', sizeof (web));
memset (path, '/0', sizeof (path));
memset (file, '/0', sizeof (file));
memset (cookie, '/0', sizeof (cookie));
memset (date, '/0', sizeof (date));
memset (response.head, '/0', sizeof (response.head));
memset (response.body, '/0', sizeof (response.body));
toLowerCase (argv[1]);
analyseWebAddress (argv[1], protocal, web, path, file, &port);
printf ("protocal:%s/n", protocal);
printf ("web:%s/n", web);
printf ("path:%s/n", path);
printf ("file:%s/n", file);
printf ("port:%d/n/n", port);
//不解释,不懂的话,程序不用看了
if ((host = gethostbyname (web)) == NULL)
{
fprintf (stderr, "Get host name error,%s/n", strerror (errno));
exit (1);
}
if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf (stderr, "Socket error,%s/n", strerror (errno));
exit (1);
}
//不解释,不懂的话,程序不用看了
bzero (&server_addr, sizeof (server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons (port);
server_addr.sin_addr = *((struct in_addr *) host->h_addr);
if (connect
(sockfd, (struct sockaddr *) (&server_addr),
sizeof (struct sockaddr)) == -1)
{
fprintf (stderr, "Connect Error:%s/r/n", strerror (errno));
exit (1);
}
sprintf (date,
"pwuser=lenky&pwpwd=你的密码&hideid=0&cktime=31536000&jumpurl=http%3A%2F%2Fbbs.ctbu.edu.cn%2Findex.php&step=2");
//sprintf函数不解释,不懂的话,说明C语言不过关
//数据"pwuser=lenky&pwpwd=你的密码&hideid=0&cktime=31536000&jumpurl=http%3A%2F%2Fbbs.ctbu.edu.cn%2Findex.php&step=2"的
//获得可以用ethereal查看,如果懂http,请直接分析html代码(可用程序自动分析)
sprintf (request,
"POST %s/%s HTTP/1.1/r/nKeep-Alive:300/r/nAccept:*/*/r/nAccept-Language:zh-cn/r/nUser-Agent:Mozilla/4.0(compatible;MSIE5.01;Windows NT 5.0)/r/nHost:%s:%d/r/nConnection:keep-alive/r/n",
path, file, web, port);
addParameterToRequest
("Content-Type:application/x-www-form-urlencoded/r/n");
sprintf (tempDate, "Content-Length:%d/r/n/r/n", strlen (date));
addParameterToRequest (tempDate);
addParameterToRequest (date);
requestRun (sockfd);
printf ("/n%s/n/n", request);
printf ("response.head:%s/r/n", response.head);
printf ("response.body:%s/r/n", response.body);
//获得响应的Cookie,这个是后面发帖的证书,没有它就表示你没有登陆bbs,当然没有回帖的权限
getParameterFromResponseHeader ("Set-Cookie:", cookie);
//重新开始
memset (request, '/0', sizeof (request));
memset (protocal, '/0', sizeof (protocal));
memset (web, '/0', sizeof (web));
memset (path, '/0', sizeof (path));
memset (file, '/0', sizeof (file));
memset (date, '/0', sizeof (date));
memset (response.head, '/0', sizeof (response.head));
memset (response.body, '/0', sizeof (response.body));
toLowerCase (argv[2]);
analyseWebAddress (argv[2], protocal, web, path, file, &port);
while (1)
{
//关闭后面才能再打开,否则会出错
//可不可以不关闭,下面继续用呢?不可,我开是就是直接用,结果发现读不到数据,试了很久,
//后来猜想http是无状态协议,不保存连接,所以就先关闭再打开,结果行了,不知道到底是不是这个理,我也不清楚,还在查资料...
close (sockfd);
if ((host = gethostbyname (web)) == NULL)
{
fprintf (stderr, "Get host name error,%s/n", strerror (errno));
exit (1);
}
if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf (stderr, "Socket error,%s/n", strerror (errno));
exit (1);
}
if (connect
(sockfd, (struct sockaddr *) (&server_addr),
sizeof (struct sockaddr)) == -1)
{
fprintf (stderr, "Connect Error:%s/r/n", strerror (errno));
exit (1);
}
sprintf (date,
"atc_money=0&atc_rvrc=0&atc_title=Re33333&atc_usesign=1&atc_convert=1&atc_autourl=1&atc_content=2222222222222&step=2&action=reply&fid=16&tid=127795&editor=0atc_attachment=none");
sprintf (request,
"POST %s/%s HTTP/1.1/r/nAccept:*/*/r/nAccept-Language:zh-cn/r/nUser-Agent:Mozilla/4.0(compatible;MSIE5.01;Windows NT 5.0)/r/nHost:%s:%d/r/nConnection:Close/r/n",
path, file, web, port);
sprintf (tempDate, "Referer:%s%s:%d%s/%s/r/n", protocal, web, port,
path, file);
addParameterToRequest (tempDate);
sprintf (tempDate, "Cookie:%s/r/n", cookie);
addParameterToRequest (tempDate);
addParameterToRequest
("Content-Type:application/x-www-form-urlencoded/r/n");
sprintf (tempDate, "Content-Length:%d/r/n/r/n", strlen (date));
addParameterToRequest (tempDate);
addParameterToRequest (date);
requestRun (sockfd);
printf ("/n%s/n/n", request);
printf ("response.head:%s/r/n", response.head);
printf ("response.body:%s/r/n", response.body);
//可以用个循环模拟
//写了个小程序包含如下循环,编译后在linux下测试:time ./cs,结果用了38秒,足够对付论坛30秒的限定
//如果你计算机配置好,加大t的值就行了
for (t = 0; t < 28; t++)
for (i = 0; i < 1000; i++)
for (j = 0; j < 1000; j++)
for (k = 0; k < 100; k++)
;
//或者sleep(40);该函数在头文件unistd.h中有定义
}
exit (0);
}