admin';?>

首页 / 工作日志

无需网络,获取光猫公网IP

By admin  •  2022-02-11 13:19:59  •  47次点击
永久外链: https://i.otherhill.com/static/41ed9f838afa11ecb4842089845721cb.html
前文书 https://i.otherhill.com/index.php/topic/show/354 讲到如何使用ddns脚本,来通知DNS服务器更新公网IP.
借助第三方网站,来获取当前公网IP.提供这种IP查询的免费网站,很多.
这种方法有两大不足:
1. 网址可能会失效,或者网络拥堵,造成无法响应
2.有些网站是钓鱼网站,用这些做DDNS查询,等于告诉了运营商,此地无银.

既然光猫本身就知道自己的公网IP,为何我们要舍近求远?


1. 打开光猫的telnet.
进入  http://192.168.1.1/hidden_version_switch.gch, 勾选telnet使能.

2. 登录到光猫.
telnet 192.168.1.1 23
按提示输入光猫root帐号,密码
Login: root
Password: Pon521
每种光猫的root密码,默认值各不相同,至于如何获取自家光猫的root密码,只能靠缘份了.

3.
cd /home/httpd
vi public/index.gch
...
if (redirect_script IS NOT NULL
&& redirect_script != "N/A"
&& redirect_script != ""
&& redirect_script != "index.gch")
{
switch (redirect_script)
{
case "start.ghtml":
IMPORT FILE "frame.gch";
break;
case "get_public_ip.gch":
case "ajaxQueryDevice.gch":
case "ajaxQueryWANRate.gch":
case "ajaxWirelessSpirit.gch":
...

vi get_public_ip.gch
输入如下内容:
<%
var IsVerifyEnable = 1;
var IsCardUsed = 0;
var IsSimCard = 0;
var IsCardStatus = 0;
var IsTr069;
%>
<%
var PPP_NUM,PPP_OBJNAME,PPP_IDENTITY,PPP_HANDLE;
var PPP_TransType,PPP_WANCName,PPP_IsNAT,PPP_StrServList;
var PPP_IPAddress,PPP_ConnStatus,PPP_UpTime,PPP_DNS1,PPP_DNS2,PPP_DNS3,PPP_WorkIFMac,PPP_ConnError;
var PPP_Mode,PPP_GateWay;
var NUM =0;
PPP_OBJNAME="OBJ_ETHWANCPPP_ID";
PPP_NUM = query_list(PPP_OBJNAME, "IGD");
for(var i=0;i<PPP_NUM;i++)
{
PPP_HANDLE = create_paralist();
PPP_IDENTITY = query_identity(i);
get_inst(PPP_HANDLE, PPP_OBJNAME, PPP_IDENTITY);
PPP_IPAddress = get_para(PPP_HANDLE, "IPAddress");
=PPP_IPAddress;
destroy_paralist(PPP_HANDLE);
break;//我们只需要第一个IP,如果你有多个公网IP,需自行处理.
}
%>
保存并退出vi.

以后 http://192.168.1.1/get_public_ip.gch 即能随时查询到公网IP.


我们可以在 https://i.otherhill.com/index.php/topic/show/354  所述脚本中, 加入如下行:
enc_ip=`echo -n "$CUR_IP"  |base64`
enc_ip="LM${enc_ip}"
 
echo 'base64: '$enc_ip

rst=`$CURL -k -s --request POST --data-urlencode "xxx=$enc_ip" https://zzz.yourdomain.com/`


然后在服务器端,建立一个如下php网页index.php:
<?php
header("Content-type: text/html; charset=utf-8");

if(!$_POST || !$_POST['xxx']) return;

$enc_ip = $_POST['xxx'];

//移除前导字符.前两个字符为干扰字符
$enc_ip=substr($enc_ip,2,100);

$dec_ip = (base64_decode($enc_ip));
//判断IP是否合理 
$isValid=filter_var($dec_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
if(!$isValid) return;

//将ip写入log
$fp = @fopen('logs/ip.txt', 'w');
if ($fp)
{
    @fwrite($fp, $dec_ip);
}else{

  echo "can't open logs/ip.txt\n";
}
@fclose($fp);


然后,我们再写一个c程序,监控logs/ip.txt的改动,一旦内容发生变动.立即更新/etc/hosts, 重启nginx,等服务.至于为何还要另写一个程序来监控更改,而不是由php脚本直接来处理?
这主要是出于安全考虑.
/run/media/lixing/6T_20181101_1/proj/files/inotify_files/
#include<stdio.h>
#include<sys/inotify.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<fcntl.h> // library for fcntl function
#include <string.h>
#include <time.h>
#include "../3rdParty/iniparser/iniparser.h"


bool writeto_file(const char* file_cnt, const char* filename);

#define MAX_EVENTS 1024  /* Maximum number of events to process*/
#define LEN_NAME 200  /* Assuming that the length of the filename
won't exceed 16 bytes*/
#define EVENT_SIZE  ( sizeof (struct inotify_event) ) /*size of one event*/
#define BUF_LEN     ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME ))
/*buffer to store the data of events*/
 
int fd,wd;
dictionary* dic_ini=0;

void sig_handler(int sig){
    /* Step 5. Remove the watch descriptor and close the inotify instance*/
    inotify_rm_watch( fd, wd );
    close( fd );

    if(dic_ini)
    {
        iniparser_freedict(dic_ini);
    }
    
    exit( 0 );
}

 
#define INIFILE "./cfg.ini"

#define IP_LEN 50

struct cfg_stru{
    const char* watch_path;
    const char* watch_short_fn;//"ip.txt"
    const char* host_file;   //"/etc/hosts"
    const char* your_domain; //"yourhouse.yourdomain.com"
    const char* reload_nginx_cmd;//"sudo ./reload_nginx.sh"

} g_cs[]={{"","","",""}};
 

void handle_ip_change()
{
    int nLen = strlen(g_cs[0].watch_path) + strlen(g_cs[0].watch_short_fn)+100;

    char *special_full_path=(char*)malloc(nLen);
    strcpy(special_full_path, g_cs[0].watch_path);
    strcat(special_full_path, g_cs[0].watch_short_fn);


    FILE* fp = fopen( special_full_path, "r");
    if(!fp) 
    {
        printf("can't open file:%s\n", special_full_path);
        free(special_full_path);
        return;
    }
    free(special_full_path); special_full_path=0;

    printf("handle_ip_change\n");

    char new_ip[IP_LEN];
    char old_iphost[100];

    char* line = NULL;
    size_t len = 0;
    while ((getline(&line, &len, fp)) != -1) {
        // using printf() in all tests for consistency

        strcpy(new_ip, line);
        
        //我只取第一行
        break;
    }

    //去除空格
    int j=0;
    for(int i=0;i<IP_LEN && new_ip[i]!=0;i++)
    {
        if(new_ip[i]==0x20 
        || new_ip[i]==' ' 
        || new_ip[i]=='\t'
        || new_ip[i]=='\r'
        || new_ip[i]=='\n'
        || new_ip[i]=='\f' 
        || new_ip[i]=='\v'   
        )
        continue;

        line[j++] = new_ip[i];

    }
    line[j++]=0;
    strcpy(new_ip, line);

    printf("new_ip: %s \n", new_ip);

    if (line)
        free(line);

    fclose(fp);
    
    //2. 修改/etc/hosts文件中指定行
    fp = fopen( g_cs[0].host_file, "r");
    if(!fp) 
    { 
        return;
    }

    fseek(fp, 0, SEEK_END); // seek to end of file
    int file_size = ftell(fp); // get current file pointer
    fseek(fp, 0, SEEK_SET); // seek back to beginning of file

    char* file_cnt = (char*)malloc(file_size);
    file_cnt[0]=0;

    line=0;
    while ((getline(&line, &len, fp)) != -1) { 

        if(strstr(line, g_cs[0].your_domain)!=0)
        {
            snprintf(old_iphost, 100, "%s %s\n", new_ip, g_cs[0].your_domain);
            strcat(file_cnt, old_iphost); 
        }
        else
        {
            strcat(file_cnt, line);
        } 
    }
    if (line)
        free(line);

    fclose(fp);
    //printf("%s \n", file_cnt);
    //write new content to /etc/hosts
    time_t rawtime;
    struct tm * timeinfo;

    time ( &rawtime );
    timeinfo = localtime ( &rawtime );

    if(writeto_file(file_cnt, g_cs[0].host_file))
    {
        printf("change %s success at %s !", g_cs[0].host_file, asctime (timeinfo));
    }else{
        printf("sorry, can't open file: %s \n", g_cs[0].host_file);
    } 
 
    free(file_cnt); 

    //3. reload nginx
    system(g_cs[0].reload_nginx_cmd);

    //4. reload stunnel
}

void Usage()
{
    printf("\n"
    "usage:\nsudo ./file_notify\n"
    "under /your_path/, must exist a file: %s\n"
    "./file_notify will watch  /your_path/%s, \n once it's changed, we will read the first line as new ip,\n\n", g_cs[0].watch_short_fn,g_cs[0].watch_short_fn
    );
}


//https://linuxhint.com/inotify_api_c_language/ 
int main(int argc, char **argv){
    const char *path_to_be_watched;
    signal(SIGINT,sig_handler);

    dic_ini = iniparser_load(INIFILE);
	if (NULL == dic_ini)
    {
        const char* ini_default_cnt=""
            "[global]\n"
            "watch_path=\"/tmp/\"\n"
            "watch_short_fn=\"ip.txt\"\n"
            "host_file=\"/etc/hosts\"\n"
            "your_domain=\"yourhouse.your_domain.com\"\n"
            "reload_nginx_cmd=\"sudo ./reload_nginx.sh\" ";
        ;

        if(writeto_file(ini_default_cnt, INIFILE))
        {
             dic_ini = iniparser_load(INIFILE);   
        }

        if (NULL == dic_ini)
        {
		    printf("ERROR: load config file:%s fail!\n", INIFILE); 
		    return 0;
        }
	}
   g_cs[0].watch_path = iniparser_getstring(dic_ini, "global:watch_path", NULL);
   g_cs[0].host_file = iniparser_getstring(dic_ini, "global:host_file", NULL);
   g_cs[0].your_domain = iniparser_getstring(dic_ini, "global:your_domain", NULL);
   g_cs[0].watch_short_fn = iniparser_getstring(dic_ini, "global:watch_short_fn", NULL);
   g_cs[0].reload_nginx_cmd = iniparser_getstring(dic_ini, "global:reload_nginx_cmd", NULL);
   Usage();

    //printf("%s ,\n %s ,\n%s ,\n%s ,\n%s ,\n",
    //g_cs[0].watch_path
    //,g_cs[0].host_file
    //,g_cs[0].your_domain
    //,g_cs[0].watch_short_fn
    //,g_cs[0].reload_nginx_cmd
    //);
    path_to_be_watched = g_cs[0].watch_path;
    

    /* Step 1. Initialize inotify */
    fd = inotify_init();

    if (fcntl(fd, F_SETFL, O_NONBLOCK|O_CLOEXEC) < 0)  // error checking for fcntl
        exit(2);

    /* Step 2. Add Watch */
    wd = inotify_add_watch(fd,path_to_be_watched,IN_MODIFY | IN_CREATE);

    if(wd==-1){
        printf("Could not watch : %s\n",path_to_be_watched);
    }
    else{
        printf("Watching : %s\n",path_to_be_watched);
    }
    static int iflags = 1;

    while(1){
        int i=0,length;
        char buffer[BUF_LEN];

        /* Step 3. Read buffer*/
        length = read(fd,buffer,BUF_LEN);

        /* Step 4. Process the events which has occurred */
        while(i<length){
            struct inotify_event *event = (struct inotify_event *) &buffer[i];

            if(event->len){
                if ( event->mask & IN_CREATE ) {
                if ( event->mask & IN_ISDIR ) {
                        printf( "The directory %s was created.\n", event->name );
                    }
                    else {
                        printf( "The file %s was created.\n", event->name );
                    }
                }
                else if ( event->mask & IN_MODIFY ) {
                    if ( event->mask & IN_ISDIR ) {
                        printf( "The directory %s was modified.\n", event->name );
                    }
                    else {
                        printf( "The file %s was modified.\n", event->name );

                        if(strcmp(event->name, g_cs[0].watch_short_fn)==0)
                        {
                            //改一个文件,会调用两次,我做个标志.
                            if(2==iflags)
                            {
                                handle_ip_change();    
                            }

                            if(iflags==1)
                            {
                                iflags=2;
                            }else{
                                iflags=1;
                            } 
                        }
                    }
                }
            }
            i += EVENT_SIZE + event->len;
        }
    }

    return 0;
}
 

bool writeto_file(const char* file_cnt, const char* filename)
{
    bool bRtn = false;
    FILE* fl = fopen(filename, "w");
    if(!fl)
    {
        printf("can't write file: %s\n", filename);
        return bRtn; 
    }

    if(fwrite (file_cnt , sizeof(char), strlen(file_cnt), fl)>0)
    {
        printf("write to %s success  !\n", filename);
    }
    bRtn = true;
    fclose(fl);
    return bRtn;
} 
上面源码中有一个大BUG, 不知大家发现没有,欢迎在下评论,压缩包中已改正.

该c/c++ 源码工程打包下载(60KB):   https://otfiles.otherhill.com:12321/uploads/file/20220219/inotify_files20220219.tar.gz

最后,切记: 进入  http://192.168.1.1/hidden_version_switch.gch, 关闭telnet使能.






0 回复 | 直到2022-05-27 23:40添加回复

回复

最近更新

私信给我
生成图片 生成二维码 生成密码
清空