应用层常见协议及其实现库
DNS
利用C语言实现DNS查询和DNS响应包的解析。
1 | /* |
HTTP
利用C语言实现HTTP请求,可以采用原生Socket往端口发包,根据HTTP协议自行构造请求的方式。
但更方便的方式是使用libcurl库。自行构造Socket请求的方式既不能保证性能,又无法保证安全。
libcurl库至少是相对完善的第三方库。
详细用法,参考libcurl官方文档以及libcurl官方样例。
SMTP
SMTP一例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235/*
* 源码出处:https://blog.csdn.net/zx824/article/details/7387418
*/
#ifdef WIN32
#include <windows.h>
#include <stdio.h>
#else
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#endif
struct data6{
unsigned int d4:6;
unsigned int d3:6;
unsigned int d2:6;
unsigned int d1:6;
};
// 协议中加密部分使用的是base64方法
char con628(char c6);
void base64(char *dbuf,char *buf128,int len);
void sendemail(char *email,char *body);
int open_socket(struct sockaddr *addr);
int main()
{
char email[] = "[email protected]";
char body[] = "From: \"yyy\"<[email protected]>\r\n"
"To: \"xxx\"<[email protected]>\r\n"
"Subject: Hello\r\n\r\n"
"Hello World, Hello Email!";
sendemail(email, body);
return 0;
}
char con628(char c6)
{
char rtn = '\0';
if (c6 < 26) rtn = c6 + 65;
else if (c6 < 52) rtn = c6 + 71;
else if (c6 < 62) rtn = c6 - 4;
else if (c6 == 62) rtn = 43;
else rtn = 47;
return rtn;
}
// base64的实现
void base64(char *dbuf, char *buf128, int len)
{
struct data6 *ddd = NULL;
int i = 0;
char buf[256] = {0};
char *tmp = NULL;
char cc = '\0';
memset(buf, 0, 256);
strcpy(buf, buf128);
for(i = 1; i <= len/3; i++)
{
tmp = buf+(i-1)*3;
cc = tmp[2];
tmp[2] = tmp[0];
tmp[0] = cc;
ddd = (struct data6 *)tmp;
dbuf[(i-1)*4+0] = con628((unsigned int)ddd->d1);
dbuf[(i-1)*4+1] = con628((unsigned int)ddd->d2);
dbuf[(i-1)*4+2] = con628((unsigned int)ddd->d3);
dbuf[(i-1)*4+3] = con628((unsigned int)ddd->d4);
}
if(len%3 == 1)
{
tmp = buf+(i-1)*3;
cc = tmp[2];
tmp[2] = tmp[0];
tmp[0] = cc;
ddd = (struct data6 *)tmp;
dbuf[(i-1)*4+0] = con628((unsigned int)ddd->d1);
dbuf[(i-1)*4+1] = con628((unsigned int)ddd->d2);
dbuf[(i-1)*4+2] = '=';
dbuf[(i-1)*4+3] = '=';
}
if(len%3 == 2)
{
tmp = buf+(i-1)*3;
cc = tmp[2];
tmp[2] = tmp[0];
tmp[0] = cc;
ddd = (struct data6 *)tmp;
dbuf[(i-1)*4+0] = con628((unsigned int)ddd->d1);
dbuf[(i-1)*4+1] = con628((unsigned int)ddd->d2);
dbuf[(i-1)*4+2] = con628((unsigned int)ddd->d3);
dbuf[(i-1)*4+3] = '=';
}
return;
}
// 发送邮件
void sendemail(char *email, char *body)
{
int sockfd = 0;
struct sockaddr_in their_addr = {0};
char buf[1500] = {0};
char rbuf[1500] = {0};
char login[128] = {0};
char pass[128] = {0};
#ifdef WIN32
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 2), &WSAData);
#endif
memset(&their_addr, 0, sizeof(their_addr));
their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(25);
their_addr.sin_addr.s_addr = inet_addr("123.58.177.49");//qq smtp 服务器
// 连接邮件服务器,如果连接后没有响应,则2 秒后重新连接
sockfd = open_socket((struct sockaddr *)&their_addr);
memset(rbuf,0,1500);
while(recv(sockfd, rbuf, 1500, 0) == 0)
{
printf("reconnect...\n");
//Sleep(2);
//close(sockfd);
sockfd = open_socket((struct sockaddr *)&their_addr);
memset(rbuf,0,1500);
}
printf("%s\n", rbuf);
// EHLO
memset(buf, 0, 1500);
sprintf(buf, "EHLO abcdefg-PC\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// AUTH LOGIN
memset(buf, 0, 1500);
sprintf(buf, "AUTH LOGIN\r\n");
send(sockfd, buf, strlen(buf), 0);
printf("%s\n", buf);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// USER
memset(buf, 0, 1500);
sprintf(buf,"[email protected]");
memset(login, 0, 128);
base64(login, buf, strlen(buf));
sprintf(buf, "%s\r\n", login);
send(sockfd, buf, strlen(buf), 0);
printf("%s\n", buf);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// PASSWORD
sprintf(buf, "password");
memset(pass, 0, 128);
base64(pass, buf, strlen(buf));
sprintf(buf, "%s\r\n", pass);
send(sockfd, buf, strlen(buf), 0);
printf("%s\n", buf);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// MAIL FROM
memset(buf, 0, 1500);
sprintf(buf, "MAIL FROM: <[email protected]>\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// RCPT TO 第一个收件人
sprintf(buf, "RCPT TO:<%s>\r\n", email);
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// DATA 准备开始发送邮件内容
sprintf(buf, "DATA\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// 发送邮件内容,\r\n.\r\n内容结束标记
sprintf(buf, "%s\r\n.\r\n", body);
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// QUIT
sprintf(buf, "QUIT\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
printf("%s\n", rbuf);
// VC2005 需要使用
//closesocket(sockfd);
close(sockfd);
#ifdef WIN32
WSACleanup();
#endif
return;
}
// 打开TCP Socket连接
int open_socket(struct sockaddr *addr)
{
int sockfd = 0;
sockfd=socket(PF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
fprintf(stderr, "Open sockfd(TCP) error!\n");
exit(-1);
}
if(connect(sockfd, addr, sizeof(struct sockaddr)) < 0)
{
fprintf(stderr, "Connect sockfd(TCP) error!\n");
exit(-1);
}
return sockfd;
}
其他协议,后续学到再补充。