一、3322动态域名更新接口
接口地址
API URL
http://members.3322.net/dyndns/update
HTTP请求
GET /dyndns/update?hostname=yourhost.ourdomain.ext&myip=ipaddress&wildcard=OFF&mx=mail.exchanger.ext&backmx=NO&offline=NO HTTP/1.1
Host: members.3322.net
Authorization: Basic username:password
User-Agent: myclient/1.0 me@null.net
参数说明
username:password
该参数必选, 用户名和密码用来进行身份认证,必须使用 base64进行编码
hostname=host.3322.org
该参数必选, 需要更新的域名
myip=ipaddr
该参数可选, 域名对应的IP。如果不指定,则服务器将选择最佳的IP(一些Proxy会传递客户端的IP, 这会被服务器检测到)。如果传递的地址格式错误,则忽略这个参数,而用服务器检测 到的IP。
wildcard=ON|OFF
该参数可选, 该参数可选,是否支持泛域名(通配符),缺省为OFF。ON意为着 *.host.3322.org等同于host.3322.org
mx=mailexchanger
该参数可选, 指明Mail eXchanger。必须能够解析到一个IP,否则被忽略。如果不提供该参数或者 不能解析到一个IP,mx记录会被删除。
backmx=YES|NO
该参数可选, 指明前面的mx参数会被设置成备份邮件服务器,即邮件会首先发送到你的机器上,如果 不成功,才会发送到备份邮件服务器上。
offline=YES|NO Optional: Yes
该参数可选, 使域名暂时失效。
HTTP状态返回码
HTTP状态返回码为200、4XX、5XX,其中4XX表示认证错误,500表示服务器内部出错,200表示正常请求。但是动态域名客户端 请忽略HTTP返回码,而是对下面的返回值进行解析。比如返回值”interror”表示内部出错,这时对应的HTTP状态返回码是500。
返回值
更新成功
good
成功,IP地址已经成功更新,good 后面会跟着所更新的IP地址
nochg
成功,IP地址和上次请求没有变化, nochg 后面会跟着所请求的IP地址
更新出错
badauth
身份认证出错,请检查用户名和密码, 或者编码方式出错。
badsys
该域名不是动态域名,可能是其他类型的域名(智能域名、静态域名、域名转向、子域名)。
badagent
由于发送大量垃圾数据,客户端名称被系统封杀。
参数出错
notfqdn
没有提供域名参数,必须提供一个在公云注册的动态域名域名。
nohost
域名不存在,请检查域名是否填写正确。
!donator
必须是收费用户,才能使用 offline 离线功能。
!yours
该域名存在,但是不是该用户所有。
!active
该域名被系统关闭,请联系公云客服人员。
abuse
该域名由于段时间大量发送更新请求,被系统禁止,请联系公云客服人员。
服务器出错
dnserr
DNS 服务器更新失败。
interror
服务器内部严重错误,比如数据库出错或者DNS服务器出错。
参考网站:http://www.pubyun.com/wiki/帮助:api
二、以下代码是通过HTTP实现3322的域名更新
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#if HAVE_SNPRINTF
#define snprintf(x, y, z...) snprintf(x, y, ## z)
#else
#define snprintf(x, y, z...) sprintf(x, ## z)
#endif
#define BUFFER_SIZE (4*1024-1)
#define MAX_WAITRESPONSE_WAIT (24*3600)
#define HTTP_HOST_LEN 256 /* 主机名长度 */
#define HTTP_DEF_PORT 80 /* 连接的缺省端口 */
#define HTTP_BUF_SIZE 1024 /* 缓冲区的大小 */
#define HTTP_FILENAME_LEN 256 /* 文件名长度 */
enum {
UPDATERES_OK = 0,
UPDATERES_ERROR,
UPDATERES_SHUTDOWN,
};
static const char *server = "members.3322.net";//http://members.3322.net/dyndns/update
static char port[10] = {"80"};
static volatile int client_sockfd;
static int wildcard = 0;
static char *mx = NULL;
static int options = 0;
static char table64[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
void base64Encode(char *intext, char *output)
{
unsigned char ibuf[3];
unsigned char obuf[4];
int i;
int inputparts;
while(*intext) {
for (i = inputparts = 0; i < 3; i++) {
if(*intext) {
inputparts++;
ibuf[i] = *intext;
intext++;
}
else
ibuf[i] = 0;
}
obuf [0] = (ibuf [0] & 0xFC) >> 2;
obuf [1] = ((ibuf [0] & 0x03) << 4) | ((ibuf [1] & 0xF0) >> 4);
obuf [2] = ((ibuf [1] & 0x0F) << 2) | ((ibuf [2] & 0xC0) >> 6);
obuf [3] = ibuf [2] & 0x3F;
switch(inputparts) {
case 1: /* only one byte read */
sprintf(output, "%c%c==",
table64[obuf[0]],
table64[obuf[1]]);
break;
case 2: /* two bytes read */
sprintf(output, "%c%c%c=",
table64[obuf[0]],
table64[obuf[1]],
table64[obuf[2]]);
break;
default:
sprintf(output, "%c%c%c%c",
table64[obuf[0]],
table64[obuf[1]],
table64[obuf[2]],
table64[obuf[3]] );
break;
}
output += 4;
}
*output=0;
}
#if 0
void http_parse_request_url(const char *buf, char *host, unsigned short *port, char *file_name)
{
int length = 0;
char port_buf[8];
char *buf_end = (char *)(buf + strlen(buf));
char *begin, *host_end, *colon, *file;
/* 查找主机的开始位置 */
begin = const_cast<char*>(strstr(buf, "//"));
begin = (begin ? begin + 2 : const_cast<char*>(buf));
colon = strchr(begin, ':');
host_end = strchr(begin, '/');
if (host_end == NULL)
{
host_end = buf_end;
}
else
{
/* 得到文件名 */
file = strrchr(host_end, '/');
if (file && (file + 1) != buf_end)
strcpy(file_name, file + 1);
}
if (colon) /* 得到端口号 */
{
colon++;
length = host_end - colon;
memcpy(port_buf, colon, length);
port_buf[length] = 0;
*port = atoi(port_buf);
host_end = colon - 1;
}
/* 得到主机信息 */
length = host_end - begin;
memcpy(host, begin, length);
host[length] = 0;
}
char *http_get_type_by_suffix(const char *suffix)
{
struct doc_type *type;
for (type = file_type; type->suffix; type++)
{
if (strcmp(type->suffix, suffix) == 0)
return type->type;
}
return NULL;
}
void http_parse_request_cmd(char *buf, int buflen, char *file_name, char *suffix)
{
int length = 0;
char *begin, *end, *bias;
/* 查找 URL 的开始位置 */
begin = strchr(buf, ' ');
begin += 1;
/* 查找 URL 的结束位置 */
end = strchr(begin, ' ');
*end = 0;
bias = strrchr(begin, '/');
length = end - bias;
/* 找到文件名的开始位置 */
if ((*bias == '/') || (*bias == '\\'))
{
bias++;
length--;
}
/* 得到文件名 */
if (length > 0)
{
memcpy(file_name, bias, length);
file_name[length] = 0;
begin = strchr(file_name, '.');
if (begin)
strcpy(suffix, begin + 1);
}
}
int http_send_response(SOCKET soc, char *buf, int buf_len)
{
int read_len, file_len, hdr_len, send_len;
char *type;
char read_buf[HTTP_BUF_SIZE];
char http_header[HTTP_BUF_SIZE];
char file_name[HTTP_FILENAME_LEN] = "index.html", suffix[16] = "html";
FILE *res_file;
/* 得到文件名和后缀 */
http_parse_request_cmd(buf, buf_len, file_name, suffix);
res_file = fopen(file_name, "rb+"); /* 用二进制格式打开文件 */
if (res_file == NULL)
{
printf("[Web] The file [%s] is not existed\n", file_name);
return 0;
}
fseek(res_file, 0, SEEK_END);
file_len = ftell(res_file);
fseek(res_file, 0, SEEK_SET);
type = http_get_type_by_suffix(suffix); /* 文件对应的 Content-Type */
if (type == NULL)
{
printf("[Web] There is not the related content type\n");
return 0;
}
/* 构造 HTTP 首部,并发送 */
hdr_len = sprintf(http_header, http_res_hdr_tmpl, file_len, type);
send_len = send(soc, http_header, hdr_len, 0);
//send_len=1;
if (send_len == SOCKET_ERROR)
{
fclose(res_file);
printf("[Web] Fail to send, error = %d\n", WSAGetLastError());
return 0;
}
do /* 发送文件, HTTP 的消息体 */
{
read_len = fread(read_buf, sizeof(char), HTTP_BUF_SIZE, res_file);
if (read_len > 0)
{
send_len = send(soc, read_buf, read_len, 0);
file_len -= read_len;
}
} while ((read_len > 0) && (file_len > 0));
fclose(res_file);
return 1;
}
#endif
void show_message(char *fmt, ...)
{
fprintf(stderr, "message incomplete because your OS sucks: %s\n", fmt);
}
int do_connect(int *sock, char *host, char *port)
{
struct sockaddr_in address;
int len;
int result;
struct hostent *hostinfo;
struct servent *servinfo;
// set up the socket
if((*sock=socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
return(-1);
}
address.sin_family = AF_INET;
// get the host address
hostinfo = gethostbyname(host);
if(!hostinfo)
{
close(*sock);
return(-1);
}
address.sin_addr = *(struct in_addr *)*hostinfo->h_addr_list;
printf("%s \n",inet_ntoa(address.sin_addr));
#if 0
char **p;
for(p=hostinfo->h_addr_list;*p!=0;p++)
{
struct in_addr in;
char **q;
memcpy(&address.sin_addr,*p,sizeof(address.sin_addr));
printf("%s\t%s",inet_ntoa(address),hostinfo->h_name);/* 鍏朵腑璋冪敤浜唅net_ntoa()鍑芥暟 */
}
// get the host port
servinfo = getservbyname(port, "tcp");
if(servinfo)
{
address.sin_port = servinfo->s_port;
}
else
{
address.sin_port = htons(atoi(port));
}
#endif
printf("port: %s \n", port);
address.sin_port = htons(atoi(port));
// connect the socket
len = sizeof(address);
if((result=connect(*sock, (struct sockaddr *)&address, len)) == -1)
{
close(*sock);
return(-1);
}
printf("connect successful \n");
return 0;
}
int read_input(void *buf, int len)
{
fd_set readfds;
int max_fd;
struct timeval tv;
int ret;
int bread = -1;
tv.tv_sec = 5;
tv.tv_usec = 0;
// set up our fdset and timeout
FD_ZERO(&readfds);
FD_SET(client_sockfd, &readfds);
max_fd = client_sockfd;
ret = select(max_fd + 1, &readfds, NULL, NULL, &tv);
if(ret == -1)
{
fprintf(stderr, "select:\n");
}
else if(ret == 0)
{
fprintf(stderr, "timeout\n");
}
else
{
/* if we woke up on client_sockfd do the data passing */
if(FD_ISSET(client_sockfd, &readfds))
{
if((bread=recv(client_sockfd, buf, len, 0)) == -1)
{
fprintf(stderr, "error recv()ing reply\n");
}
}
else
{
fprintf(stderr, "error: case not handled.");
}
}
return(bread);
}
void output(void *buf)
{
fd_set writefds;
int max_fd;
struct timeval tv;
int ret;
tv.tv_sec = 5;
tv.tv_usec = 0;
// set up our fdset and timeout
FD_ZERO(&writefds);
FD_SET(client_sockfd, &writefds);
max_fd = client_sockfd;
ret = select(max_fd + 1, NULL, &writefds, NULL, &tv);
if(ret == -1)
{
fprintf(stderr, "erro message:");
}
else if(ret == 0)
{
fprintf(stderr, "erro message:");
}
else
{
/* if we woke up on client_sockfd do the data passing */
if(FD_ISSET(client_sockfd, &writefds))
{
if(send(client_sockfd, buf, strlen(buf), 0) == -1)
{
fprintf(stderr, "erro message:");
}
}
else
{
fprintf(stderr, "erro message:");
}
}
}
int ddnsUpdate(char *hostname, char *user, char* password, int flag)
{
char userpass[256] = {0};
char auth[512] = {0};
char buf[BUFFER_SIZE+1];
char *bp = buf;
int bytes;
int btot;
int ret;
int retval = UPDATERES_OK;
buf[BUFFER_SIZE] = '\0';
if(do_connect((int*)&client_sockfd, server, port) != 0)
{
return 1;
}
snprintf(buf, BUFFER_SIZE, "GET %s?", "/dyndns/update");
output(buf);
snprintf(buf, BUFFER_SIZE, "%s=%s", "hostname", hostname);
output(buf);
#if 0
if(address != NULL)
{
snprintf(buf, BUFFER_SIZE, "%s=%s&", "myip", address);
output(buf);
}
snprintf(buf, BUFFER_SIZE, "%s=%s&", "wildcard", wildcard ? "ON" : "OFF");
output(buf);
if(mx != NULL && *mx != '\0')
{
snprintf(buf, BUFFER_SIZE, "%s=%s&", "mx", mx);
output(buf);
}
snprintf(buf, BUFFER_SIZE, "%s=%s&", "backmx", "NO");
output(buf);
if(options != 0)
{
snprintf(buf, BUFFER_SIZE, "%s=%s&", "offline", "yes");
output(buf);
}
#endif
snprintf(buf, BUFFER_SIZE, " HTTP/1.1\015\012");
output(buf);
snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", hostname);
output(buf);
sprintf(userpass, "%s:%s", user, password);
base64Encode(userpass, auth);
snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
output(buf);
snprintf(buf, BUFFER_SIZE, "User-Agent: %s-01 Linux (%s)\015\012", "itnvr-update", "by Liwh");
output(buf);
snprintf(buf, BUFFER_SIZE, "\015\012");
output(buf);
bp = buf;
bytes = 0;
btot = 0;
while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
{
bp += bytes;
btot += bytes;
fprintf(stderr, "btot\n");
}
close(client_sockfd);
buf[btot] = '\0';
fprintf(stderr, "server output: %s\n", buf);
if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
{
ret = -1;
}
switch(ret)
{
case -1:
show_message("strange server response, are you connecting to the right server?\n");
retval = UPDATERES_ERROR;
break;
case 200:
if(strstr(buf, "\ngood ") != NULL)
{
printf("request successful\n");
}
else
{
if(strstr(buf, "\nnohost") != NULL)
{
show_message("invalid hostname: %s\n", hostname);
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\nnotfqdn") != NULL)
{
show_message("malformed hostname: %s\n", hostname);
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\n!yours") != NULL)
{
show_message("host \"%s\" is not under your control\n", hostname);
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\nabuse") != NULL)
{
show_message("host \"%s\" has been blocked for abuse\n", hostname);
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\nnochg") != NULL)
{
show_message("%s says that your IP address has not changed since the last update\n", server);
retval = UPDATERES_OK;
}
else if(strstr(buf, "\nbadauth") != NULL)
{
show_message("authentication failure\n");
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\nbadsys") != NULL)
{
show_message("invalid system parameter\n");
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\nbadagent") != NULL)
{
show_message("this useragent has been blocked\n");
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\nnumhost") != NULL)
{
show_message("Too many or too few hosts found\n");
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\ndnserr") != NULL)
{
char *p = strstr(buf, "\ndnserr");
show_message("dyndns internal error, please report this number to ");
retval = UPDATERES_ERROR;
}
else if(strstr(buf, "\n911") != NULL)
{
show_message("Ahhhh! call 911!\n");
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\n999") != NULL)
{
show_message("Ahhhh! call 999!\n");
retval = UPDATERES_SHUTDOWN;
}
else if(strstr(buf, "\n!donator") != NULL)
{
show_message("a feature requested is only available to donators, please donate.\n", hostname);
retval = UPDATERES_OK;
}
// this one should be last as it is a stupid string to signify waits
// with as it is so short
else if(strstr(buf, "\nw") != NULL)
{
int howlong = 0;
char *p = strstr(buf, "\nw");
char reason[256];
char mult;
// get time and reason
if(strlen(p) >= 2)
{
sscanf(p, "%d%c %255[^\r\n]", &howlong, &mult, reason);
if(mult == 'h')
{
howlong *= 3600;
}
else if(mult == 'm')
{
howlong *= 60;
}
if(howlong > MAX_WAITRESPONSE_WAIT)
{
howlong = MAX_WAITRESPONSE_WAIT;
};
}
else
{
sprintf(reason, "problem parsing reason for wait response");
}
show_message("Wait response received, waiting for %d seconds before next update.\n", howlong);
show_message("Wait response reason");
sleep(howlong);
retval = UPDATERES_ERROR;
}
else
{
show_message("error processing request\n");
fprintf(stderr, "==== server output: ====\n%s\n", buf);
retval = UPDATERES_ERROR;
}
}
break;
case 401:
show_message("authentication failure\n");
retval = UPDATERES_SHUTDOWN;
break;
default:
// reuse the auth buffer
*auth = '\0';
sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
show_message("unknown return code: %d\n", ret);
fprintf(stderr, "server response: %s\n", auth);
retval = UPDATERES_ERROR;
break;
}
return(retval);
}
执行成功后,3322的域名管理中,相应的域名的IP地址发生改动。
hostname = xxxx.8866.org
user = root
password = itnvr2014
61.160.239.25
port: 80
connect successful
btot
timeout
server output: HTTP/1.1 200 OK
Server: nginx
Date: Wed, 11 Jun 2014 01:57:28 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
13
good 183.28.38.109
0
request successful