Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal and external IP address translation #1089

Closed
2 tasks done
Siriling opened this issue Jun 21, 2023 · 19 comments
Closed
2 tasks done

Internal and external IP address translation #1089

Siriling opened this issue Jun 21, 2023 · 19 comments
Labels
🤔 Idea Tell us your ideas 📝 Needs more info An issue that has too little information

Comments

@Siriling
Copy link

Siriling commented Jun 21, 2023

Description

Hello,
I really like this app, it has a nice interface and a lot of customization. As a docker application panel or console, it still lacks a very necessary function, that is internal and external IP address translation.
Internal and external address conversion, it is very convenient to access through the IP address in the internal network, and access through the domain name in the external network. The following is the internal and external conversion file written by me personally, providing a reference, hoping to add this function to homarr.

zhuan.php:

<?php

/**
 * 功能:隐藏内网ip,起始页自动切换内外网,点击链接自动切换内外网
 * External to External:https://start.demo.com:81/zhuan.php?lan=:1315&wan=https://start.demo.com:81&name=auto
 * Internal to internal:10.10.10.248/zhuan.php?lan=:1315&wan=https://start.demo.com:81&name=auto
 * Internal and external IP address translation:../zhuan.php?lan=:1315&wan=https://homelab.demo.com:81&name=switch
 * 
 * Unraid:../zhuan.php?lan=:80&wan=https://unraid.demo.com:81&name=unraid
 * Other application:../zhuan.php?lan=13:80&wan=https://qb.demo.com:81&name=server
 */

//internal ip
$local_host = '10.10.10.';

//server and rooter ip
$unraid_ip='10.10.10.254';
$ikuai_ip='10.10.10.253';
$openwrt_ip='10.10.10.252';
$tp_ip='10.10.10.251';
$asus_ip='10.10.10.250';
$truenas_ip='10.10.10.249';
$vpnserver_ip='10.10.10.248';

//other application ip
$server_ip='10.10.10.2';

if (is_array($_GET) && count($_GET) > 0)//判断是否有Get参数
{

    //获取当前的域或ip
    $host = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']);
    $temp = strstr ($host, ':', true);

    // if(!$_SERVER["HTTP_X_FORWARDED_FOR"]) //用来源ip或域名判断
    if(strpos($temp,$local_host) !== false) //判断当前的域或ip是否为内网ip
    {
        //url is internal
        if(isset($_GET["lan"])) //判断所需要的lan参数是否存在,isset用来检测变量是否设置,返回true or false
        {
            if(isset($_GET["name"])) {
                if($_GET["name"]=="switch") {
                    $url = $_GET["wan"]; //Internal to external
                }
                else if ($_GET["name"]=="unraid") { //判断name选择对应的ip
                    $url = "http://".$unraid_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="ikuai") {
                    $url = "http://".$ikuai_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="openwrt") {
                    $url = "http://".$openwrt_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="tplink") {
                    $url = "http://".$tp_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="asus") {
                    $url = "http://".$asus_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="truenas") {
                    $url = "http://".$truenas_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="vpnserver") {
                    $url = "http://".$vpnserver_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="server") {
                    $url = "http://".$server_ip.$_GET["lan"];
                }
                else if ($_GET["name"]=="lskypro") { 
                    $url = "http://".$unraid_ip.$_GET["lan"]; //兰空图床特殊处理(已废弃)
                }
                elseif ($_GET["name"]=="auto") {
                    $url = "http://".$vpnserver_ip.$_GET["lan"]; //已在本地内网无需跳转
                }
                else {
                    $url = "http://".$vpnserver_ip.$_GET["lan"]; //无匹配上的name,则跳回起始页
                }
            }
            else {
                $url = "http://".$_GET["lan"];  //没有name需写全内网ip,不加上http协议报403
            }
            header("Location: $url");
            exit();
        }
    }
    else
    {
        //url is external
        if(isset($_GET["wan"])) //判断所需要的wan参数是否存在
        {
            if($_GET["name"]=="switch") {
                $url = "http://".$vpnserver_ip.$_GET["lan"]; //External to Internal
                // $url = "http://".($temp?$temp:$host).":81";
            }
            else if($_GET["name"]=="lskypro") {
                $url = "http://".$_GET["wan"]; //兰空图床特殊处理(已废弃)
            }
            else if($_GET["name"]=="tplink") {
                $url = "http://".$_GET["wan"]; //TP路由器特殊处理(已废弃)
            }
            else if ($_GET["name"]=="auto") {
                if (strpos($_SERVER["HTTP_X_FORWARDED_FOR"],$local_host) !== false) { //来源ip与本地网段一致则自动跳回内网
                    $url = "http://".$vpnserver_ip.$_GET["lan"];
                }
                else {
                    $url = $_GET["wan"];
                }
            }
            else {
                $url = $_GET["wan"]; ///没有name参数默认走wan后的域名
            }
            header("Location: $url");
            exit();
        }
    }
}

//Get参数不存在,lan和wan的参数不存在输出404
header("http/1.1 404 not found");
header("status: 404 not found");
//echo 'echo 404';//直接输出页面错误信息
header('location: /404.html');
exit();
?>

images:
image
Internal and external IP address translation
image
application
image

我是中文使用者,所以提问是来自于Google翻译,对于可能会带来一些误解实在抱歉。Thank you!

Please tick the boxes

@Siriling Siriling added the 🤔 Idea Tell us your ideas label Jun 21, 2023
@ajnart
Copy link
Owner

ajnart commented Jun 29, 2023

I am so sorry I don't understand everything with this php code. Can you explain to me the feature you'd like more in depth, why and how are important for me to understand your motivation behind this

@ajnart ajnart added the 📝 Needs more info An issue that has too little information label Jun 29, 2023
@Siriling
Copy link
Author

I am so sorry I don't understand everything with this php code. Can you explain to me the feature you'd like more in depth, why and how are important for me to understand your motivation behind this

To put it simply, I use the intranet ip to access the service when I am at home, and use the domain name to access the service when I am out of town. Click the same application icon, and it will judge whether you are in the intranet according to your network environment. If it is an intranet, it will be accessed through a static ip address. If it is not an intranet, it will be accessed through a set domain name.

@Siriling Siriling closed this as not planned Won't fix, can't repro, duplicate, stale Jun 29, 2023
@Siriling
Copy link
Author

Siriling commented Jun 29, 2023

I accidentally clicked on closed, sorry.

The advantage of this is:

  1. Faster access when on the internal network.
  2. The web page automatically switches between the internal and external network environment, making it more convenient to use.

@Siriling Siriling reopened this Jun 29, 2023
@Siriling Siriling reopened this Jun 29, 2023
@ajnart
Copy link
Owner

ajnart commented Jun 29, 2023

I am so sorry I don't understand everything with this php code. Can you explain to me the feature you'd like more in depth, why and how are important for me to understand your motivation behind this

To put it simply, I use the intranet ip to access the service when I am at home, and use the domain name to access the service when I am out of town. Click the same application icon, and it will judge whether you are in the intranet according to your network environment. If it is an intranet, it will be accessed through a static ip address. If it is not an intranet, it will be accessed through a set domain name.

I see. Would you happen to know how to do that or resources where I can find where to implement it ?

@Siriling Siriling reopened this Jun 30, 2023
@Siriling
Copy link
Author

I am so sorry I don't understand everything with this php code. Can you explain to me the feature you'd like more in depth, why and how are important for me to understand your motivation behind this

To put it simply, I use the intranet ip to access the service when I am at home, and use the domain name to access the service when I am out of town. Click the same application icon, and it will judge whether you are in the intranet according to your network environment. If it is an intranet, it will be accessed through a static ip address. If it is not an intranet, it will be accessed through a set domain name.

I see. Would you happen to know how to do that or resources where I can find where to implement it ?

I saw it from the blibli video website, this conversion file is developed based on PHP, but the configuration file provided by the video author cannot meet my intranet multi-application access requirements. After I understood the implementation method, I improved the conversion file and realized the effect I wanted. The file is zhuan.php above. But I don't know how to implement it on homarr. If it is a PHP service, add this file and write the URL to achieve it.

I wrote a simple tutorial, don't know if it can help

@DearLi123111
Copy link

Yes, I also really need this feature. To be honest, I am not sure about the purpose of setting internal and external addresses in Homarr when configuring the app. Whether I am at home or outside, clicking the app in Homarr always opens the external address.

1 similar comment
@DearLi111
Copy link

Yes, I also really need this feature. To be honest, I am not sure about the purpose of setting internal and external addresses in Homarr when configuring the app. Whether I am at home or outside, clicking the app in Homarr always opens the external address.

@ajnart
Copy link
Owner

ajnart commented Jul 23, 2023

okok, so from chatGPT I got the following

function isIPAddress(url) {
  // Regular expression to match an IP address
  const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;

  // Check if the provided URL is an IP address
  return ipRegex.test(url);
}

// Usage
const currentURL = window.location.hostname;
const isUserUsingIPAddress = isIPAddress(currentURL);

It would make it possible to detect if the user is using an IP address to connect to homarr instead of a subdomain. Would that work for you guys ?
You'd need to open homarr on like 192.186.1.200:80 when at home and homarr.website.com/ when outside of home.

We detect that you are at home because the URL you are using is an IP and not a website.

@Siriling
Copy link
Author

okok, so from chatGPT I got the following

function isIPAddress(url) {
  // Regular expression to match an IP address
  const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;

  // Check if the provided URL is an IP address
  return ipRegex.test(url);
}

// Usage
const currentURL = window.location.hostname;
const isUserUsingIPAddress = isIPAddress(currentURL);

It would make it possible to detect if the user is using an IP address to connect to homarr instead of a subdomain. Would that work for you guys ? You'd need to open homarr on like 192.186.1.200:80 when at home and homarr.website.com/ when outside of home.

We detect that you are at home because the URL you are using is an IP and not a website.

Yes, that might work. How this is used in the homarr?

@caesay
Copy link

caesay commented Jul 24, 2023

I don't know if my requirements are the same as this post but I think the problem is similar. If it's not similar enough I can open a new issue. I access my dashboard through an https cloudflare domain secured/authenticated by cloudflare zero trust access (both when I'm at home and away from home). I expect homarr to communicate with local services via ip address - but it would be ideal if it could render/pass-through iframe-based intranet content for me, especially DashDot.

Here is an example:

In this case, if I configure Homarr to use https://dash.mydashboard.com the iframes work, both at home and away from home, but Homarr can't communicate with Dash, because the end point is authenticated, so the panel never shows. If I configure Homarr to use http://192.168.x.x, everything works at home, but the iframes break when away from home.

There could be two different solutions.

  1. Provide an internal and external address in the Dash widget. So it uses http://192.168.x.x for talking to Dash itself but uses https://dash.mydashboard.com for rendering iframes
  2. You could solve this by having Homarr serve up (naïve reverse proxy) the necessary dash graphs (which I think is what is being asked for here?). So I would configure http://192.168.x.x as the endpoint for dash, but when the page is loaded at an external domain (eg. https://dash.mydashboard.com) it would render an iframe with an address like https://dash.mydashboard.com/dashproxy?... instead of the IP address

@manuel-rw
Copy link
Collaborator

manuel-rw commented Jul 24, 2023

Hello guys 👋.
I want to post my take on this too.

okok, so from chatGPT I got the following

function isIPAddress(url) {
  // Regular expression to match an IP address
  const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;

  // Check if the provided URL is an IP address
  return ipRegex.test(url);
}

// Usage
const currentURL = window.location.hostname;
const isUserUsingIPAddress = isIPAddress(currentURL);

It would make it possible to detect if the user is using an IP address to connect to homarr instead of a subdomain. Would that work for you guys ?
You'd need to open homarr on like 192.186.1.200:80 when at home and homarr.website.com/ when outside of home.

We detect that you are at home because the URL you are using is an IP and not a website.

This is an incredibly stupid way of detecting, if an IP is internal. For starters, an IP doesn't have to mean that it's internal at all - You can easily expose via IPv4 and IPv6 with port forwarding on almost any consumer router, unless your ISP is doing some janky NAT / abstraction.

For example, the IP 10.36.183.61 could be external. You could test, wether an IP uses a specific subnet (eg. 192 prefix, /24, /32, /26), but that still doesn't make it clear, where Homarr is located. For example, you can use the above mentioned IP locally as well. Many networks of big companies are like that (and probably some enthusiasts here have this too).

Things will get even worse with IPv6. Also, I often set my own host names with DNS locally - those would be local too, but your solution would mark them as external which is not true.

Therefore, a simple Regex is by far not enough to "detect", if an IP is internal or external.

However, I do have a suggestion for this issue.
The user (or at least the administrator) should always know, what subnet they are running. Why not just ask them for it?

Homarr could simply have a UI, where you could add internal IPs to a list. If the current user accesses Homarr from any of these IPs, the internal logic will be used.

However, I want to emphasize something here. In my opinion, this issue is somewhat unnecessary. You should never expose tools like Homarr, Dash. and others anyway. The root cause of issues like this one here are bad network configuration and not using proper tools (VPN, tunnels, ...).
However, I understand that not everyone has the same priorities as I do and they might just want to have it as easy as possible or invest little time in self hosting - that's understandable. This feature should benefit most users and may be a good addition anyway.

Switches and edge cases often add additional complexity. If we are going to implement this, I think we should pay attention to keeping it as simple as possible and making sure, that the users understand what's going on.

@ajnart
Copy link
Owner

ajnart commented Jul 24, 2023

@caesay in your case it’s not really solvable. Homarr doesn’t communicate with the internal address of dashdot. That’s why you don’t need an app for it, you can just set up the URL inside of the widget config.
Your browser will do the request and render the iframe.
So, in theory if it is authed correctly it should render it properly.

@manuel-rw so do you think we should close this issue as not planned ?

@manuel-rw
Copy link
Collaborator

From my point of view, this question always comes up, when the original network configuration is not well done or when there are some weird limitations (user can't port forward, user can't use VPNs, ...). Personally, I wouldn't implement it, as it is only a workaround for problems, that should be solved differently. However, many people have requested this. If the community really wants this, we should allow for it - even though it might not be the most ideal solution.

I certainly would not give this any high priority, but if anyone wants to implement a solution for this, I would be open to review it.

@taos15
Copy link
Contributor

taos15 commented Jul 24, 2023

I think is not necessary on most setup, you can use your reverse proxy (ai use traefik but any one will do) and just make a hist overwrite on your local dns (on my pi-hole ai created a host overwrite file in the dnsmask.d folder that point my host name to my local reverse proxy) that way when you are away from home your you can access your home at dashboard.yourdomain.tld when local pi-hole will intersect the request to dashboard.yourdomain.tld and send it to your local server not leaving the lan (intranet).

@caesay
Copy link

caesay commented Jul 25, 2023

@ajnart Re dashdot, as soon as I enable auth on my dashdot https url, the widgets continue working until I refresh the page. I can still access dashdot fine by opening it in a new tab (because I'm already signed in) but I can't access it in Homarr. After auth is enabled, in the browser console I just see 500 errors for https://$SECURE_HOMARR_URL/api/trpc/dashDot.info,dashDot.info?batch=1&input={"0":{"json":{"url":"$SECURE_DASHDOT_URL"}},"1":{"json":{"url":"$SECURE_DASHDOT_URL2"}}}. The widgets render "Cannot acquire information from dash.". The iframes don't even attempt to appear. If the iframes did render, they would work just fine, because my browser can access dashdot fine. Note that the error 500 failing request is to Homarr server, not to dashdot. I assume this is to get some kind of request to get dashdot configuration? Should I open a new issue about it?

@manuel-rw
Copy link
Collaborator

The iframes don't even attempt to appear.

That is normal. Homarr won't even attempt to show them, since your API connection is failing.

Note that the error 500 failing request is to Homarr server, not to dashdot. I assume this is to get some kind of request to get dashdot configuration?

That is intentional and normal. Homarr often acts as a very simple proxy server. It receives the request for data from clients, connects to the applications (eg. Dash.) using the credentials and then returns the data. This way, credentials will never come to the client and sensitive data will not be publicly available (MAC, IP, passwords, ...).

Have you checked, if you configured the integration on the Dash. app, when you enabled authentication? The 500 tRPC error just means, that the server was unable to communicate. Please check the logs for further details - they'll reveal more detailed information.

@Siriling
Copy link
Author

Hello guys 👋. I want to post my take on this too.

okok, so from chatGPT I got the following

function isIPAddress(url) {
  // Regular expression to match an IP address
  const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;

  // Check if the provided URL is an IP address
  return ipRegex.test(url);
}

// Usage
const currentURL = window.location.hostname;
const isUserUsingIPAddress = isIPAddress(currentURL);

It would make it possible to detect if the user is using an IP address to connect to homarr instead of a subdomain. Would that work for you guys ?
You'd need to open homarr on like 192.186.1.200:80 when at home and homarr.website.com/ when outside of home.
We detect that you are at home because the URL you are using is an IP and not a website.

This is an incredibly stupid way of detecting, if an IP is internal. For starters, an IP doesn't have to mean that it's internal at all - You can easily expose via IPv4 and IPv6 with port forwarding on almost any consumer router, unless your ISP is doing some janky NAT / abstraction.

For example, the IP 10.36.183.61 could be external. You could test, wether an IP uses a specific subnet (eg. 192 prefix, /24, /32, /26), but that still doesn't make it clear, where Homarr is located. For example, you can use the above mentioned IP locally as well. Many networks of big companies are like that (and probably some enthusiasts here have this too).

Things will get even worse with IPv6. Also, I often set my own host names with DNS locally - those would be local too, but your solution would mark them as external which is not true.

Therefore, a simple Regex is by far not enough to "detect", if an IP is internal or external.

However, I do have a suggestion for this issue. The user (or at least the administrator) should always know, what subnet they are running. Why not just ask them for it?

Homarr could simply have a UI, where you could add internal IPs to a list. If the current user accesses Homarr from any of these IPs, the internal logic will be used.

However, I want to emphasize something here. In my opinion, this issue is somewhat unnecessary. You should never expose tools like Homarr, Dash. and others anyway. The root cause of issues like this one here are bad network configuration and not using proper tools (VPN, tunnels, ...). However, I understand that not everyone has the same priorities as I do and they might just want to have it as easy as possible or invest little time in self hosting - that's understandable. This feature should benefit most users and may be a good addition anyway.

Switches and edge cases often add additional complexity. If we are going to implement this, I think we should pay attention to keeping it as simple as possible and making sure, that the users understand what's going on.

Hello, the original php code has solved this problem very well. Judging by ip and domain name, the intranet segment needs to be manually set by yourself. In this way, you only need to set a URL on the home page of the browser, and then navigate to the next page or It is said that the operation of switching between the internal and external network of the console is senseless, and it only needs to click the mouse to connect and access. Regarding disclosure and security issues, homarr already has a login interface, I think this is not a problem, just like your emby or jellyfish service is forwarded, you also need to set a password for the web interface.

@Meierschlumpf
Copy link
Collaborator

We decided to not deal with networking / ips / domains in the following issue: #2189 (comment)

Because of that we will not implement this

@Meierschlumpf Meierschlumpf closed this as not planned Won't fix, can't repro, duplicate, stale Mar 4, 2025
@github-project-automation github-project-automation bot moved this from 🆕 New to ✅ Done in Homarr Kanban Mar 4, 2025
@caesay
Copy link

caesay commented Mar 5, 2025

I stopped using Homarr because of this issue. Homarr may have to use an internal address to access other services which is potentially different from what the user uses / has access to.

  • Homarr can access other docker containers on the local docker network, which the user does not have access to.
  • Accessing Homarr (and other containers) via the internet will almost certainly go through a proxy with SSO/auth so Homarr can not use that url to access the services.
  • Sometimes there are local domains which can be used by the user to access local services which bypass auth.

When I last tried to use Homarr, this was impossible to reconcile. I can only provide a single url for a service. If I give Homarr the external one, then it can't reach the service through the SSO and will not render the iframes etc (even though those iframes would work for me in my browser because I am authenticated). If I give Homarr the internal ones, it will render the iframes since it can reach the service, but those iframes will break for me because my browser can not reach them.

I don't have a dog in this fight any more because I've already moved on and coded my own dashboard which supports this, but I just can't see how this is not an important feature. Impossible to use Homarr unless doing the most basic internal-only thing and you build your network to explicitly support this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤔 Idea Tell us your ideas 📝 Needs more info An issue that has too little information
Projects
Status: ✅ Done
Development

No branches or pull requests

8 participants