/** * UPnP PortMapper - A tool for managing port forwardings via UPnP * Copyright (C) 2015 Christoph Pirkl <christoph at users.sourceforge.net> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * */ package org.chris.portmapper.router.weupnp; import java.net.MalformedURLException; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import org.bitlet.weupnp.GatewayDevice; import org.bitlet.weupnp.PortMappingEntry; import org.chris.portmapper.model.PortMapping; import org.chris.portmapper.model.Protocol; import org.chris.portmapper.router.AbstractRouter; import org.chris.portmapper.router.IRouter; import org.chris.portmapper.router.RouterException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class is an implements an {@link IRouter} using the weupnp library's {@link GatewayDevice}. */ public class WeUPnPRouter extends AbstractRouter { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final GatewayDevice device; WeUPnPRouter(final GatewayDevice device) { super(device.getFriendlyName()); this.device = device; } @Override public void addPortMapping(final PortMapping mapping) throws RouterException { try { device.addPortMapping(mapping.getExternalPort(), mapping.getInternalPort(), mapping.getInternalClient(), mapping.getProtocol().getName(), mapping.getDescription()); } catch (final Exception e) { throw new RouterException("Could not add portmapping", e); } } @Override public void addPortMappings(final Collection<PortMapping> mappings) throws RouterException { for (final PortMapping mapping : mappings) { this.addPortMapping(mapping); } } @Override public void disconnect() { // noting to do right now } @Override public String getExternalIPAddress() throws RouterException { try { return device.getExternalIPAddress(); } catch (final Exception e) { throw new RouterException("Could not get external IP address", e); } } @Override public String getInternalHostName() { final String url = device.getPresentationURL(); if (url == null || url.trim().length() == 0) { return null; } try { return new URL(url).getHost(); } catch (final MalformedURLException e) { logger.warn("Could not get URL for internal host name '" + url + "'", e); return url; } } @Override public int getInternalPort() throws RouterException { String url = device.getPresentationURL(); if (url == null) { url = device.getURLBase(); logger.info("Presentation url is null: use url base '{}'", url); } if (url == null) { throw new RouterException("Presentation URL and URL base are null"); } try { return new URL(url).getPort(); } catch (final MalformedURLException e) { throw new RouterException("Could not get internal port from URL '" + url + "'", e); } } @Override public Collection<PortMapping> getPortMappings() throws RouterException { final Collection<PortMapping> mappings = new LinkedList<>(); boolean morePortMappings = true; int index = 0; while (morePortMappings) { final PortMappingEntry entry = new PortMappingEntry(); try { logger.debug("Getting port mapping {}...", index); if (!device.getGenericPortMappingEntry(index, entry)) { throw new RuntimeException(); } logger.debug("Got port mapping {}: {}", index, entry); } catch (final Exception e) { morePortMappings = false; logger.debug("Got an exception with message '{}‘ for index {}, stop getting more mappings", e.getMessage(), index); } if (entry.getProtocol() != null) { final Protocol protocol = entry.getProtocol().equalsIgnoreCase("TCP") ? Protocol.TCP : Protocol.UDP; final PortMapping m = new PortMapping(protocol, entry.getRemoteHost(), entry.getExternalPort(), entry.getInternalClient(), entry.getInternalPort(), entry.getPortMappingDescription()); mappings.add(m); } else { logger.debug("Got null port mapping for index {}", index); } index++; } return mappings; } @Override public void logRouterInfo() throws RouterException { final Map<String, String> info = new HashMap<>(); info.put("friendlyName", device.getFriendlyName()); info.put("manufacturer", device.getManufacturer()); info.put("modelDescription", device.getModelDescription()); final SortedSet<String> sortedKeys = new TreeSet<>(info.keySet()); for (final String key : sortedKeys) { final String value = info.get(key); logger.info("Router Info: {} \t= {}", key, value); } logger.info("def loc: {}", device.getLocation()); logger.info("device type: {}", device.getDeviceType()); } @Override public void removeMapping(final PortMapping mapping) throws RouterException { this.removePortMapping(mapping.getProtocol(), mapping.getRemoteHost(), mapping.getExternalPort()); } @Override public void removePortMapping(final Protocol protocol, final String remoteHost, final int externalPort) throws RouterException { try { device.deletePortMapping(externalPort, protocol.getName()); } catch (final Exception e) { throw new RouterException("Could not delete port mapping", e); } } }