LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1389|回复: 1

FC6下如何设置NAT和开启uPnP

[复制链接]
发表于 2007-8-25 02:17:49 | 显示全部楼层 |阅读模式
现在我的网络结构是这样的:
路由器通过DHCP自动获得外网IP地址,路由器的内网地址是:192.168.1.1
我的机器接到路由器上,地址是192.168.1.102
ifconfig命令查看的结果如下:

eth0      Link encap:Ethernet  HWaddr 00:14:2A5:09:70  
          inet addr:192.168.1.102  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::214:2aff:fed5:970/64 Scopeink
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:94053 errors:0 dropped:0 overruns:0 frame:0
          TX packets:66192 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:123236029 (117.5 MiB)  TX bytes:6348095 (6.0 MiB)
          Interrupt:21 Base address:0x4000

lo        Link encapocal Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:181 errors:0 dropped:0 overruns:0 frame:0
          TX packets:181 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:34754 (33.9 KiB)  TX bytes:34754 (33.9 KiB)

iptables -L 命令执行的结果如下:
#iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
RH-Firewall-1-INPUT  all  --  anywhere             anywhere            

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
RH-Firewall-1-INPUT  all  --  anywhere             anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain RH-Firewall-1-INPUT (2 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     icmp --  anywhere             anywhere            icmp any
ACCEPT     esp  --  anywhere             anywhere            
ACCEPT     ah   --  anywhere             anywhere            
ACCEPT     udp  --  anywhere             224.0.0.251         udp dpt:mdns
ACCEPT     udp  --  anywhere             anywhere            udp dpt:ipp
ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:ipp
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited


现在我要写一个程序,用UPnP的功能实现端口的自动映射,

在windows下程序我已经按照以下的步骤实现了:
(1)XP操作系统安装UPnP支持组件
(2)开启UPnP和SSDP服务
(3)设置TP-Link路由器,转发规则->UPnP设置->开启uPnP
  (4) 程序加入对UPnP的支持

现在我要在linux下实现这个功能,路由器的uPnP我已经开启了,关键是如何实现操作系统对UPnP的支持, 我的操作系统信息:
# uname -a
Linux cnhnyu 2.6.20-1.2962.fc6 #1 SMP Tue Jun 19 19:27:14 EDT 2007 i686 i686 i386 GNU/Linux

我已经安装了linuxigd-1.0,upnpd这个程序也可用
我查了一些资料,要求用iptables开启NAT,然后作以下的配置:
配置

1. 增加多播路由

# route add -net 239.0.0.0 netmask 255.0.0.0 eth0

2. 为iptables建议一个软链接

# cd /usr/sbin
# ln -s /sbin/iptables ./

启动UPnP

# upnpd ppp0 eth0

诊断UPnP运行状态

# tail /var/log/messages

如果能够看到:

Dec  14 16:01:49 doorway -- MARK --
Dec  14 16:02:15 doorway upnpd:
The Linux UPnP Internet Gateway Device Ver
0.92 by Dime (dime@gulfsales.com)

Dec  14 16:02:15 doorway upnpd:
Special Thanks for Intel's Open Source SDK
and original author Genmei Mori's work.

则说明UPnP已经成功启动。

他这里用的是启动UPnP用的是以下命令:
# upnpd ppp0 eth0
这里是拨号网络,我按照这种方法试了一下,但是不行,于是我改为
# upnpd dhcp eth0
但是仍然不行,现在实在是找不到好的解决方法。

????请问我该如何正确的开启uPnP的功能以及如何用iptables来设置NAT ?



我写了一个测试程序,代码如下:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>


#define SEARCH_TARGET        ("urn:schemas-upnp-org:device:InternetGatewayDevice:1")
#define UPNPADDR                0xFAFFFFEF  /* 239.255.255.250 */
#define UPNPPORT                1900


int GetIP_v4_and_v6_linux(int family, char *address, int size);

char szLocalIP[20] = {0};

int main(void)
{
        char szFindMsg[256] = {0};
        char buffer[10240] = {0};
        int s, nLen;
        struct sockaddr_in addr;
      
        GetIP_v4_and_v6_linux(AF_INET, szLocalIP, sizeof(szLocalIP) );
        printf("%s\n", szLocalIP);

        sprintf(szFindMsg, "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: %d\r\nST: %s\r\n\r\n", 6, SEARCH_TARGET);

        s = socket(AF_INET, SOCK_DGRAM, 0);
        fcntl(s,F_SETFL, O_NONBLOCK);
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(UPNPPORT);
        addr.sin_addr.s_addr = UPNPADDR;
        sendto(s, szFindMsg, strlen(szFindMsg), 0, (struct sockaddr *)&addr, sizeof(addr));
      
        printf("Send SSDP Request:\n%s\n", szFindMsg);
   
        sleep(1);

        nLen = recv(s, buffer, sizeof(buffer), 0);
        fprintf(stderr, "nLen = %d, %s\n", nLen, strerror(errno));
      
        close(s);

        printf("Recv SSDP Response:\n%s\n", buffer);
      
        return 0;
}


int GetIP_v4_and_v6_linux(int family, char *address, int size)
{
    struct ifaddrs *ifap0, *ifap;
    char buf[NI_MAXHOST];
    char *interface = "eth0";
    struct sockaddr_in *addr4;
    struct sockaddr_in6 *addr6;
    int ret;
   
    if( NULL == address ) {
        return -1;
    }
    if(getifaddrs(&ifap0)) {
        return -1;
    }
    for( ifap = ifap0; ifap != NULL; ifap=ifap->ifa_next){
        if(strcmp(interface, ifap->ifa_name) != 0) continue;
        if(ifap->ifa_addr==NULL) continue;
        if ((ifap->ifa_flags & IFF_UP) == 0) continue;
        if(family != ifap->ifa_addr->sa_family) continue;

        if(AF_INET == ifap->ifa_addr->sa_family) {
            addr4 = (struct sockaddr_in *)ifap->ifa_addr;
            if ( NULL != inet_ntop(ifap->ifa_addr->sa_family,
                    (void *)&(addr4->sin_addr), buf, NI_MAXHOST) ){
                if(size <= strlen(buf) ) break;
                strcpy(address, buf);
                freeifaddrs(ifap0);
                return 0;
            }
            else break;
        }
        else if(AF_INET6 == ifap->ifa_addr->sa_family) {
            addr6 = (struct sockaddr_in6 *)ifap->ifa_addr;
            if(IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)){
                continue;
            }
            if(IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)){
                continue;
            }
            if(IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)){
                continue;
            }
            if(IN6_IS_ADDR_UNSPECIFIED(&addr6->sin6_addr)){
                continue;
            }
            if(IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)){
                continue;
            }
            if ( NULL != inet_ntop(ifap->ifa_addr->sa_family,
                    (void *)&(addr6->sin6_addr), buf, NI_MAXHOST) ){
                if(size <= strlen(buf) ) break;
                strcpy(address, buf);
                freeifaddrs(ifap0);
                return 0;
            }
            else break;
        }
    }

    freeifaddrs(ifap0);
    return -1;
}




如果linux操作系统支持uPnP而且路由器开启了uPnP功能的话,那么这个程序就能收到路由器的反馈消息,但是现在消息收不到,很可能是操作系统现在还不支持uPnP,所以我现在要解决的就是上面要说的问题。

希望对uPnP, iptables以及NAT熟悉的兄弟给个建议或者解决的方法,在此先行谢过了。

原帖发在:http://bbs.chinaunix.net/viewthr ... page%3D1#pid7261137
 楼主| 发表于 2007-8-28 00:04:16 | 显示全部楼层
该问题的解决方法:
关闭防火墙。在linux(至少FC6和Debian,我亲自试过)下不需要安装其他的软件就支持uPnP,
Debian下默认不需要关闭防火墙就支持,而FC6下需要关闭防火墙。

该问题得到两位热心的兄弟的帮忙:
1)陶兄
blog.filia.cn
filiasoc.blogspot.com
2)温兄
http://blog.chinaunix.net/u/2389/index.html

在此,对他们表示感谢。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表