android apk网络程序怎么bind少于1024的端口
对于 1024以内的端口,默认只提供给系统使用,外部应用是没有权限使用的,如果想要外部访问不带8080 ,则需要在服务端,设置一条如下iptable 指令;把端口号设置为80就可以省略不写。iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080// 8080 是服务器绑定的端口号,也可以改换...
对于 1024以内的端口,默认只提供给系统使用,外部应用是没有权限使用的,如果想要外部访问不带8080 ,则需要在服务端,设置一条如下iptable 指令;把端口号设置为80就可以省略不写。
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080 // 8080 是服务器绑定的端口号,也可以改换成其他
这样会把所有的8080端口都转发到80端口,可以用下面的命令指定ip和port进行转发,
iptables -t nat -A PREROUTING -d 192.168.0.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.0.1:8080
可以adb shell后直接执行命令,当然得root才行。执行后可以用 iptables -L -n -t nat 查看一下执行的结果,
可以看到命令已经成功执行,如果要删除可以用下面的命令,
iptables -t nat -D PREROUTING -d 192.168.0.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.0.1:8080
执行完后,同样可以执行 iptables -L -n -t nat 看一下结果,发现设置的规则已经被删除。
经验证,开启root权限后或者eng版本可行,由于开启root权限将引起无法预料的安全性问题,是否有不开启root权限能达到同样效果的解决方案?
那就要把这条命令放到系统里面去执行,并且开放一个接口。
客制化一套API出来,可参考如下。在启动http服务时,设置true, 在关闭服务器或者服务器挂掉时,设置false。
--- a/frameworks/base/core/java/android/os/INetworkManagementService.aidl
+++ b/frameworks/base/core/java/android/os/INetworkManagementService.aidl
@@ -618,4 +618,9 @@ interface INetworkManagementService
/**
*
* @hide
*/
void setPortNat(boolean enable,String gateway);
--- a/frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
+++ b/frameworks/base/services/core/java/com/android/server/NetworkManagementService.java
@@ -3143,4 +3143,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub
throw e.rethrowAsParcelableException();
}
}
/**
*
*
* */
public void setPortNat(boolean enable,String gateway) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
mConnector.execute("firewall", "port_nat", enable ? 1 : 0,gateway);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
--- a/system/netd/server/FirewallController.h
+++ b/system/netd/server/FirewallController.h
@@ -83,6 +83,9 @@ public:
static const char* LOCAL_STANDBY;
static const char* ICMPV6_TYPES[];
int setPortNat(bool enable,const char* gateway);
--- a/system/netd/server/CommandListener.cpp
+++ b/system/netd/server/CommandListener.cpp
@@ -1696,6 +1696,23 @@ int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
}
///@}
if (!strcmp(argv[1], "port_nat")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: firewall set_port_nat <bool>",
false);
return 0;
}
bool enable = atoi(argv[2]) == 1;
int res = sFirewallCtrl->setPortNat(enable,argv[3]);
return sendGenericOkFail(cli, res);
}
--- a/system/netd/server/FirewallController.cpp
+++ b/system/netd/server/FirewallController.cpp
@@ -774,3 +774,25 @@ int FirewallController::setEgressProtoRule(const char* proto, FirewallRule rule)
return res;
}
int FirewallController::setPortNat(bool enable,const char* gateway) {
int res = 0;
IptablesTarget target = V4;
// bool startFlag = false;
enable = true;
if(enable)
{
ALOGE("httpd server start, all dest port 80 stream nat to 8080");
char const* port =":8080";
const char *gatewayPort;
char buf[30];
strcpy(buf,gateway);
strcat(buf,port);
gatewayPort=(const char*)buf;
ALOGE("httpd gateway= %s,gatewayPort= %s",gateway,gatewayPort);
//every time remove old rules
res |= execIptables(target, "-t", "nat","-D","PREROUTING","-d",gateway,"-p", "tcp","--dport", "80","-j","DNAT","--to-destination",gatewayPort,NULL);
res |= execIptables(target, "-t", "nat","-D","PREROUTING","-d","192.168.42.129","-p", "tcp","--dport", "80","-j","DNAT","--to-destination","192.168.42.129:8080",NULL);
res |= execIptables(target, "-t", "nat","-A","PREROUTING","-d",gateway,"-p", "tcp","--dport", "80","-j","DNAT","--to-destination",gatewayPort,NULL);
res |= execIptables(target, "-t", "nat","-A","PREROUTING","-d","192.168.42.129","-p", "tcp","--dport", "80","-j","DNAT","--to-destination","192.168.42.129:8080",NULL);
}else{
ALOGD("httpd server stop, clear the 80 to 8080 port nat chain");
}
return res;
}
这里发现了一个问题,就是有时候wifi和usbthering切换的时候,会导致所有的rules被清除掉,这样就会出现问题。解决这个问题的思路就是在清除的时候把规则重新加进去,对FirewallController所有有可能清除rules的函数里面打log,发现这个是在clearUdpForwarding函数里面执行的
//Delete the old IPTABLE rule
res |= execIptables(target, "-F", "oem_fwd", NULL);
res |= execIptables(target, "-t", "nat", "-F", "PREROUTING", NULL);
于是在这个之后重新把我们的规则加上,
int FirewallController::clearUdpForwarding(const char* inInterface, const char* extInterface) {
IptablesTarget target = V4;
int res = 0;
char const* port =":8080";
char buf[GATEWAY_BUF_LENGTH];
if(inInterface==NULL || extInterface==NULL){
ALOGW("clearUdpForwarding: invalid args");
} else {
ALOGD("clearUdpForwarding: %s-%s", inInterface, extInterface);
}
//Delete the old IPTABLE rule
res |= execIptables(target, "-F", "oem_fwd", NULL);
res |= execIptables(target, "-t", "nat", "-F", "PREROUTING", NULL);
property_set("net.rndis.client", "");
//重新把规则加上
if (strlen(mGateway)){
strcpy(buf,mGateway);
strcat(buf,port);
res |= execIptables(target, "-t", "nat","-A","PREROUTING","-d",mGateway,"-p", "tcp","--dport", "80","-j","DNAT","--to-destination",(const char*)buf,NULL);
res |= execIptables(target, "-t", "nat","-A","PREROUTING","-d","192.168.42.129","-p", "tcp","--dport", "80","-j","DNAT","--to-destination","192.168.42.129:8080",NULL);
ALOGE("...clearUdpForwarding end....");
}
return res;
}
这里需要把传进来的gateway保存一下,
int FirewallController::setPortNat(bool enable,const char* gateway) {
...
strcpy(mGateway,gateway);
...
}
构造函数里
--- a/system/netd/server/FirewallController.cpp
+++ b/system/netd/server/FirewallController.cpp
@@ -77,6 +77,7 @@ const char* FirewallController::ICMPV6_TYPES[] = {
FirewallController::FirewallController(void) {
// If no rules are set, it's in BLACKLIST mode
mFirewallType = BLACKLIST;
+ memset(mGateway,0,GATEWAY_BUF_LENGTH);
}
同时在头文件里面添加
--- a/system/netd/server/FirewallController.h
+++ b/system/netd/server/FirewallController.h
@@ -41,7 +41,7 @@ enum FirewallChinaRule { MOBILE, WIFI };
#define PROTOCOL_GRE 47
#define PROTOCOL_ICMP 1
-
+#define GATEWAY_BUF_LENGTH 64
static const char* NSIOT_WHITE_LIST[] = {
"1.1.1.1",
"1.2.3.4",
@@ -116,7 +116,7 @@ private:
int createChain(const char*, const char*, FirewallType);
FirewallType getFirewallType(ChildChain);
int refreshPkgUidList(const char *file_path, int uid, bool add);
-
+ char mGateway[GATEWAY_BUF_LENGTH];
};
另外上面的清除代码存在问题,当规则不存在的时候,去执行的话会报错的。如果不清除的话,这个规则会越来越多,可能会带来一些问题。
//every time remove old rules
res |= execIptables(target, "-t", "nat","-D","PREROUTING","-d",gateway,"-p", "tcp","--dport", "80","-j","DNAT","--to-destination",gatewayPort,NULL);
res |= execIptables(target, "-t", "nat","-D","PREROUTING","-d","192.168.42.129","-p", "tcp","--dport", "80","-j","DNAT","--to-destination","192.168.42.129:8080",NULL);
改为下面的,就不会报错,不是针对某条规则,而是把所有规则都清除,这样每次设置新规则前就会把所有的旧规则清除。
//Delete the old IPTABLE rule
res |= execIptables(target, "-F", "oem_fwd", NULL);
res |= execIptables(target, "-t", "nat", "-F", "PREROUTING", NULL);
调用的方法很简单
INetworkManagementService mNetworkService = INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
try {
mNetworkService.setPortNat(true); //打开
} catch (RemoteException e) {
}
try {
mNetworkService.setPortNat(false); //关闭
} catch (RemoteException e) {
}
更多推荐
所有评论(0)