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. 几句话就能让你理解:this、闭包、原型链

    以下是个人对这三个老大难的总结(最近一直在学习原生JS,翻了不少书,不少文档,虽然还是新手,但我会继续坚持走我自己的路) 原型链 所有对象都是基于Object.prototype,Object.pro ...

  2. 基于Cesium1.26地图API下的GeoServer2.9.0服务器跨域设置

    遇到的问题: 最近基于Cesium来做3D模型的地图开发,在访问自己发布的WMS服务之后,遇到了GeoServer跨域问题. 调用这个WMS服务的时候,浏览器(我用Chrome)开发者工具报错: 控制 ...

  3. js与native交互

    js与native交互 UIWebView Native调用JS,使用stringByEvaluatingJavaScriptFromString来解释执行js脚本. //script即为要执行的js ...

  4. iOS开发 引用第三方库出现duplicate symbol时的处理方法

      该篇文章是我自己从我的新浪博客上摘抄过来的, 原文链接为: http://blog.sina.com.cn/s/blog_dcc636350102wat5.html     在iOS开发中, 难免 ...

  5. python基础(1) 变量类型

    变量赋值: python中的变量不需要类型声明 每个变量在使用前必须赋值,变量赋值以后才会被创建 变量在内存中创建时,包括变量的标识.名称和数据这些信息. EX: #!/usr/bin/python ...

  6. 怎么样在Myeclipse中配置JDK?

    1.首先电脑上安装JDK 2.打开Myeclipse  >>  Window  >>  Preferences  如图1: 图1 2.Preferences  >> ...

  7. Sublime Text 3 快捷键总结

    以下是个人总结不完全的快捷键总汇,祝愿各位顺利解放自己的鼠标. 选择类 Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本. Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同 ...

  8. mybatis-generator-gui--一个mybatis代码自动生成界面工具

    mybatis-generator-gui是什么 介绍mybatis-generator-gui之前,有必要介绍一下什么是mybatis generator(熟悉的同学可以跳过这一节).我们都知道,通 ...

  9. 迭代字典中的key和value

    字典是python中十分重要的一个内容. 今天我们来谈谈,在一个 for 循环中,能否同时迭代 key和value?当然可以咯. dict 对象的 items() 方法返回的值: >>&g ...

  10. 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题

    精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合 ...