ngrok反向隧道

前情提要:小明与小白各有一台主机,两台主机在同一内网,小明想直接通过内网ssh到小白的主机上。但是小白的ip地址会不断的变化,而小明不想每次都要麻烦小白查看ip。于是小明催生了一个想法:写个脚本在自己的主机运行输出小白的ip。

01 获取本机ip地址

> cat ip-server.c

#include  <stdio.h>
#include  <sys/socket.h>
#include  <unistd.h>
#include  <sys/types.h>
#include  <netinet/in.h>
#include  <stdlib.h>
#include  <time.h>
#include  <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>

#define  SERVER_PORT 20000  //  define the defualt connect port id
#define  LENGTH_OF_LISTEN_QUEUE 10  // length of listen queue in server
#define  BUFFER_SIZE 255 

unsigned long getNumIP(char* dev){//eth0
    int fd;
    struct ifreq ifr;
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    /* I want to get an IPv4 IP address */
    ifr.ifr_addr.sa_family = AF_INET;
    /* I want IP address attached to "eth0" */
    strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
    int rtn=ioctl(fd, SIOCGIFADDR, &ifr);
    close(fd);
    if(rtn==-1) return rtn;
    /* display result */
    unsigned long numIP=((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
    return numIP;
}
int main(int argc, char** argv)
{
       int  servfd,clifd;
       struct  sockaddr_in servaddr,cliaddr;

       if  ((servfd  =  socket(AF_INET,SOCK_STREAM, 0 ))  <   0 )
         {
              printf( " create socket error!\n " );
              exit( 1 );
       } 

       bzero( & servaddr, sizeof (servaddr));

       servaddr.sin_family  =  AF_INET;
       servaddr.sin_port  =  htons(SERVER_PORT);
       servaddr.sin_addr.s_addr  =  htons(INADDR_ANY);

       if  (bind(servfd,( struct  sockaddr * ) & servaddr, sizeof (servaddr)) < 0 )
         {
              printf( " bind to port %d failure!\n " ,SERVER_PORT);
              exit( 1 );
       } 

        if  (listen(servfd,LENGTH_OF_LISTEN_QUEUE)  <   0 )
         {
              printf( " call listen failure!\n " );
              exit( 1 );
       } 

        while  ( 1 )
         { // server loop will nerver exit unless any body kill the process 

              char  buf[BUFFER_SIZE];
              long  timestamp;
              socklen_t length  =   sizeof (cliaddr);
              clifd  =  accept(servfd,( struct  sockaddr * ) & cliaddr, & length);

               if  (clifd  <   0 )
                {
                     printf( " error comes when call accept!\n " );
                     break ;
              } 

               // inet_ntop(INET_ADDRSTRLEN,cliaddr.sin_addr,buf,BUFFER_SIZE);
        //////////
        unsigned long numIP=getNumIP("ppp0");
        if(numIP==-1)//-1 error
        numIP=getNumIP("eth0");
         //printf("eth0:%lld\n",numIP);
        if(numIP==-1) numIP=getNumIP("wlan0");
         if(numIP==-1) numIP=0;
         struct in_addr iaddr;
         iaddr.s_addr=numIP;
         char* ip = inet_ntoa(iaddr);
        ////////
         strcpy(buf, ip );
         send(clifd,buf,strlen(buf), 0 );
         close(clifd);
        } // exit 

        close(servfd);
        return   0 ;
}

编译

> gcc ip-server.c -o ip-server

02 启动ngrok客户端

这里使用的是1.7版本,官方的2.0及之后非开源。

> cat start_ngrok.sh

#可以加入开机自启动脚本,如/etc/rc.local中
PRE=$HOME/bin/ngrok
NGROK_DIR=$PRE/ngrok1.7
$PRE/ip-server &
$NGROK_DIR/ngrok -log=stdout -config=$NGROK_DIR/ngrok.cfg -subdomain theUniqName 20000 > /dev/null 2>&1 &

其中ngrok.cfg中指定如下的内容:

server_addr: "xxxHostName:4443"

trust_host_root_certs: false

启动ngrok后,服务器xxxHostName上会开通一个子域名theUniqName,通过访问theUniqName.xxxHostName:80可以获取到ngrok客户端机器上的20000端口的内容。

在不添加-subdomain参数时服务端会选择一个未使用的端口,建立到你的本地的隧道。每次你重新建立隧道时给你分配的端口很可能不同。

另外还可以使用sunny博客博主提供的ngrok服务(www.ngrok.cc),用户注册后可以创建固定端口的隧道,并分配一个clientID,ngrok启动时指定这个clientID即可。

03 测试使用

在其他机器上通过curl来获取(因为ip-server程序中仅仅输出一行ip地址,而没有http头部信息,所以curl会检测出来并直接输出原内容)

> curl 隧道地址

另外,随手附上终止ngrok程序的脚本(ngrok在连接不到服务器时可能会不断尝试连接而不是自行退出)

> cat stop.sh

pid_1=$(ps ax|grep [i]p-server|awk '{print $1}')
pid_2=$(ps ax|grep [n]grok1.7/ngrok|awk '{print $1}')
if [ -z $pid_1 ];then
    echo 'ip_server not running'
else
    kill $pid_1
fi
if [ -z $pid_2 ];then
        echo 'ngrok not running'
else
        kill -9 $pid_2
fi
echo 'stopped ip-server and ngrok!'

04 END

反向隧道通常用来打通内网主机与公网主机的连接,可以方便web开发等。那么它与ssh反向隧道相比有什么优势呢?除了可以创建子域名的方式比较方便外,暂时也不太清楚,但是比ssh功能上要纯粹的多。

ngrok反向隧道--获取内网IP的更多相关文章

  1. 通过js获取内网ip和外网ip的简单方法 ...

    今天遇到了一个需求,需要获取用户当前的内网ip, 找了半天终于找到了方法,遂将找到的方法记录下来,留给需要的人. 1,获取内网ip function getIP(callback) { let rec ...

  2. xss实现获取内网ip

    前提得浏览器支持webRTC,测试的时候google浏览器测试成功,火狐浏览器不支持webRTC, 再在xss平台直接复制如下js代码: function form_ip(ip,port){ var ...

  3. JAVA 优先获取外网Ip,再获取内网Ip

    1.获取内网Ip private String getLocalhostIp(){ String hostAddress = ""; try { InetAddress addre ...

  4. Python获取内网IP

    Python 获取本机内网IP 本文记录使用Python获取本机IP的两种方法. 通过hostname来获取本机IP import socket print(socket.gethostbyname( ...

  5. (转)js获取内网ip地址,操作系统,浏览器版本等信息

    这次呢,说一下使用js获取用户电脑的ip信息,刚开始只是想获取用户ip,后来就顺带着获取了操作系统和浏览器信息. 先说下获取用户ip地址,包括像ipv4,ipv6,掩码等内容,但是大部分都要根据浏览器 ...

  6. 获取本机外网ip和内网ip

    获取本机外网ip //获取本机的公网IP public static string GetIP() { string tempip = ""; try { WebRequest r ...

  7. js获取设备内网ip

    可以直接使用,不需要导入其他配置 看代码 1 <script> 2 //获取内网ip 3 var RTCPeerConnection = window.RTCPeerConnection ...

  8. 根据Request获取客户端IP 内网IP及外网IP

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr() ,这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实 ...

  9. C#获取内网和外网IP

    写了个小客户端,里面用到了获取内网和外网的IP地址,代码如下: // InnerIP var ipHost = Dns.Resolve(Dns.GetHostName()); ]; innerIP = ...

随机推荐

  1. js与java正则表达式处理字符串问题

    在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要.正则表达式就是用于描述这些规则的工具.换句话说,正则表达式就是记录文本规则的代码.合理使用正则表达式确实会为程序员省去很多字 ...

  2. 在Thinkphp中使用AJAX实现无刷新分页

    在Thinkphp目录的Lib\ORG\Util\目录里新建AjaxPage.class.php,写入一下内容: <?php // +------------------------------ ...

  3. js数组转换问题

    一维数组转多维数组 var arr=[1,2,3,4,5,6,7,8,9,10]; function splitArray(arr,size){ var result = []; var tempAr ...

  4. SharePoint 2013 开发教程

    做了SharePoint有三年了,大家经常会问到,你的SharePoint是怎么学的,想想自己的水平,也不过是初级开发罢了.因为,SharePoint开发需要接触的东西太多了,Windows操作系统. ...

  5. Atittit.研发公司的组织架构与部门架构总结

    Atittit.研发公司的组织架构与部门架构总结 1. archi组织架构与 部门规划2 1.1. 最高五大组织机构2 1.2. 宗教事务部2 1.3. 制度与重大会议委员会2 1.4. 纠纷处理部: ...

  6. iOS学习15之OC集合

    1.数组类 1> 回顾C语言数组 数组是一个有序的集合, 来存储相同数据类型的元素. 通过下标访问数组中的元素,下标从 0 开始. 2> 数组 数组是一个有序的集合,OC中的数组只能存储对 ...

  7. seL4之hello-2旅途(完成更新)

    seL4之hello-2旅途 2016/11/19 13:15:38 If you like my blog, please buy me a cup of coffee. 回顾上周 seL4运行环境 ...

  8. 【转】JavaScript常用代码书写规范

    javascript 代码规范 代码规范我们应该遵循古老的原则:“能做并不意味着应该做”. 全局命名空间污染 总是将代码包裹在一个立即的函数表达式里面,形成一个独立的模块. 不推荐 1 2 3 var ...

  9. JAVA并发编程J.U.C学习总结

    前言 学习了一段时间J.U.C,打算做个小结,个人感觉总结还是非常重要,要不然总感觉知识点零零散散的. 有错误也欢迎指正,大家共同进步: 另外,转载请注明链接,写篇文章不容易啊,http://www. ...

  10. MySQL可视化软件Work Bench导出导入数据库

    首先打开你的work bench,输入你的密码进入主页面 A:导入数据库 在Schemas空白处右键选择Create~:建立一个数据库,然后就可以导入你的sql文件了 File-->Open S ...