Linux 通过HTTP进行域名更新

一、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

 

posted on 2014-06-10 14:13  CSlunatic  阅读(2034)  评论(0编辑  收藏  举报

导航