diff --git a/net/rtsphelper/Makefile b/net/rtsphelper/Makefile new file mode 100644 index 0000000000..f21a5a23d6 --- /dev/null +++ b/net/rtsphelper/Makefile @@ -0,0 +1,7 @@ +PLUGIN_NAME= rtsphelper +PLUGIN_VERSION= 1.2 +#PLUGIN_DEPENDS= +PLUGIN_COMMENT= RTSP Port Forwarder Helper +PLUGIN_MAINTAINER= quentin.canel@o2r.fr + +.include "../../Mk/plugins.mk" diff --git a/net/rtsphelper/pkg-descr b/net/rtsphelper/pkg-descr new file mode 100644 index 0000000000..ee0c1857e2 --- /dev/null +++ b/net/rtsphelper/pkg-descr @@ -0,0 +1 @@ +A simple helper script that opens ports to allow mis-configured RTSP servers to work behind NAT environment \ No newline at end of file diff --git a/net/rtsphelper/src/etc/inc/plugins.inc.d/rtsphelper.inc b/net/rtsphelper/src/etc/inc/plugins.inc.d/rtsphelper.inc new file mode 100644 index 0000000000..c6224149bf --- /dev/null +++ b/net/rtsphelper/src/etc/inc/plugins.inc.d/rtsphelper.inc @@ -0,0 +1,112 @@ +general->enabled == '1'; +} + +function rtsphelper_firewall($fw) +{ + if (!rtsphelper_enabled()) { + return; + } + + $fw->registerAnchor('rtsphelper', 'rdr'); + $fw->registerAnchor('rtsphelper', 'fw'); +} + +function rtsphelper_services() +{ + $services = array(); + + if (!rtsphelper_enabled()) { + return $services; + } + + $pconfig = array(); + $pconfig['name'] = 'rtsphelper'; + $pconfig['description'] = gettext('RTSP Helper'); + $pconfig['php']['restart'] = array('rtsphelper_stop', 'rtsphelper_start'); + $pconfig['php']['start'] = array('rtsphelper_start'); + $pconfig['php']['stop'] = array('rtsphelper_stop'); + $pconfig['pidfile'] = '/var/run/rtsphelper.pid'; + $services[] = $pconfig; + + return $services; +} + +function rtsphelper_start() +{ + if (!rtsphelper_enabled()) { + return; + } + + if (isvalidpid('/var/run/rtsphelper.pid')) { + return; + } + + mwexec_bg('/usr/local/bin/python3 /usr/local/opnsense/scripts/net/rtsphelper/rtsphelper.py'); +} + +function rtsphelper_stop() +{ + killbypid('/var/run/rtsphelper.pid', 'TERM', true); + mwexec('/sbin/pfctl -artsphelper -Fr 2>&1 >/dev/null'); + mwexec('/sbin/pfctl -artsphelper -Fn 2>&1 >/dev/null'); +} + +function rtsphelper_configure() +{ + return array('bootup' => array('rtsphelper_configure_do')); +} + +function rtsphelper_configure_do($verbose = false) +{ + rtsphelper_stop(); + + if (!rtsphelper_enabled()) { + return; + } + + if ($verbose) { + echo 'Starting RTSP Helper...'; + flush(); + } + + $model = new General(); + $ext_iface = (string)$model->general->ext_iface; + $ext_ifname = get_real_interface($ext_iface); + + // Log a warning if interface couldn't be resolved + // This can happen if the selected interface was deleted from the system + if ($ext_ifname == $ext_iface) { + syslog(LOG_WARNING, "rtsphelper: Interface '{$ext_iface}' could not be resolved to a device name"); + } + + $config_text = "ext_ifname={$ext_ifname}\n"; + + /* RTSP Helper access restrictions */ + foreach ($model->permissions->permission->iterateItems() as $perm) { + $network = (string)$perm->network; + $port = (string)$perm->port; + $config_text .= "allow={$network} {$port}\n"; + } + + foreach ($model->hosts->host->iterateItems() as $host) { + $ip = (string)$host->ip; + $port = (string)$host->port; + $config_text .= "forward={$ip}:{$port}\n"; + } + + /* write out the configuration */ + file_put_contents('/var/etc/rtsphelper.conf', $config_text); + rtsphelper_start(); + + if ($verbose) { + echo "done.\n"; + } +} + diff --git a/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/Api/ServiceController.php b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/Api/ServiceController.php new file mode 100644 index 0000000000..9f8e9ea694 --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/Api/ServiceController.php @@ -0,0 +1,56 @@ +request->isPost()) { + $backend = new Backend(); + $response = $backend->configdRun('rtsphelper start'); + return array("response" => $response); + } + return array("response" => array()); + } + + public function stopAction() + { + if ($this->request->isPost()) { + $backend = new Backend(); + $response = $backend->configdRun('rtsphelper stop'); + return array("response" => $response); + } + return array("response" => array()); + } + + public function restartAction() + { + if ($this->request->isPost()) { + $backend = new Backend(); + $response = $backend->configdRun('rtsphelper restart'); + return array("response" => $response); + } + return array("response" => array()); + } + + public function statusAction() + { + $backend = new Backend(); + $response = $backend->configdRun('rtsphelper status'); + return array("status" => trim($response)); + } + + public function reconfigureAction() + { + if ($this->request->isPost()) { + $backend = new Backend(); + $response = $backend->configdRun('rtsphelper configure'); + return array("response" => $response); + } + return array("response" => array()); + } +} diff --git a/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/Api/SettingsController.php b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/Api/SettingsController.php new file mode 100644 index 0000000000..6049cbe698 --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/Api/SettingsController.php @@ -0,0 +1,11 @@ +configdRun('rtsphelper connections'); + $rows = array(); + + foreach (explode("\n", $response) as $line) { + if (preg_match("/on (.*) inet proto (.*) from (.*) to (.*) port = (.*) -> (.*)/", $line, $matches)) { + $rows[] = array( + "interface" => $matches[1], + "proto" => $matches[2], + "source" => $matches[3], + "destination" => $matches[4], + "port" => $matches[5], + "redirect_to" => $matches[6] + ); + } + } + + return array("rows" => $rows); + } +} diff --git a/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/SettingsController.php b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/SettingsController.php new file mode 100644 index 0000000000..fa6d86b902 --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/SettingsController.php @@ -0,0 +1,16 @@ +view->pick('OPNsense/RTSPHelper/index'); + $this->view->formGeneral = $this->getForm("general"); + $this->view->formDialogHost = $this->getForm("dialog_host"); + $this->view->formDialogPermission = $this->getForm("dialog_permission"); + } +} diff --git a/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/dialog_host.xml b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/dialog_host.xml new file mode 100644 index 0000000000..ced57ee5ab --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/dialog_host.xml @@ -0,0 +1,14 @@ +
+ + host.ip + + text + Internal IP address. + + + host.port + + text + Port number. + +
diff --git a/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/dialog_permission.xml b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/dialog_permission.xml new file mode 100644 index 0000000000..f014745529 --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/dialog_permission.xml @@ -0,0 +1,14 @@ +
+ + permission.network + + text + Network (CIDR) or IP address. + + + permission.port + + text + Port or port range (e.g. 1024-65535). + +
diff --git a/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/general.xml b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/general.xml new file mode 100644 index 0000000000..dccafaa3a3 --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/controllers/OPNsense/RTSPHelper/forms/general.xml @@ -0,0 +1,14 @@ +
+ + general.enabled + + checkbox + Enable RTSP Helper + + + general.ext_iface + + dropdown + Select your primary WAN interface. + +
diff --git a/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/ACL/ACL.xml b/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/ACL/ACL.xml new file mode 100644 index 0000000000..d94c300888 --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/ACL/ACL.xml @@ -0,0 +1,9 @@ + + + Service: RTSP Helper + + ui/rtsphelper/* + api/rtsphelper/* + + + diff --git a/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/General.php b/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/General.php new file mode 100644 index 0000000000..c46cb4282e --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/General.php @@ -0,0 +1,9 @@ + + //OPNsense/RTSPHelper + 1.0.0 + + + + 0 + Y + + + Y + N + + + + + + Y + Please specify a valid IP address. + + + Y + Please specify a valid port number. + + + + + + + Y + Please specify a valid network (CIDR) or IP address. + + + Y + /^(\d{1,5})(?:-(\d{1,5}))?$/ + Please specify a valid port or port range (e.g. 1024-65535). + + + + + diff --git a/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/Menu/Menu.xml b/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/Menu/Menu.xml new file mode 100644 index 0000000000..447a185cb9 --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/models/OPNsense/RTSPHelper/Menu/Menu.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/net/rtsphelper/src/opnsense/mvc/app/views/OPNsense/RTSPHelper/index.volt b/net/rtsphelper/src/opnsense/mvc/app/views/OPNsense/RTSPHelper/index.volt new file mode 100644 index 0000000000..ad83cbaafc --- /dev/null +++ b/net/rtsphelper/src/opnsense/mvc/app/views/OPNsense/RTSPHelper/index.volt @@ -0,0 +1,219 @@ + +
+
+ {{ partial("layout_partials/base_form",['fields':formGeneral,'id':'frm_general_settings'])}} + +
+

{{ lang._('Hosts to enable') }}

+ + + + + + + + + + + + + + + + +
{{ lang._('IP Address') }}{{ lang._('Port') }}{{ lang._('Commands') + }}
+ +
+ +
+

{{ lang._('User specified permissions') }}

+ + + + + + + + + + + + + + + + +
{{ lang._('Network') }}{{ lang._('Port / Range') }}{{ lang._('Commands') + }}
+ +
+ +
+
+ +

+
+
+ +
+ + + + + + + + + + + + + +
{{ lang._('Interface') }}{{ lang._('Protocol') }}{{ lang._('Source') }}{{ lang._('Destination') }}{{ lang._('Port') }}{{ lang._('Redirect To') }}
+
+
+ +

+
+
+
+ +{{ partial("layout_partials/base_dialog",['fields':formDialogHost,'id':'DialogHost','label':lang._('Edit Host')])}} +{{ partial("layout_partials/base_dialog",['fields':formDialogPermission,'id':'DialogPermission','label':lang._('Edit +Permission')])}} + + \ No newline at end of file diff --git a/net/rtsphelper/src/opnsense/scripts/net/rtsphelper/configure.php b/net/rtsphelper/src/opnsense/scripts/net/rtsphelper/configure.php new file mode 100644 index 0000000000..ae1c8aacb2 --- /dev/null +++ b/net/rtsphelper/src/opnsense/scripts/net/rtsphelper/configure.php @@ -0,0 +1,8 @@ +#!/usr/local/bin/php + None: + self.forward: socket.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + def start(self, host: str, port: int) -> socket.socket | bool: + try: + self.forward.connect((host, port)) + return self.forward + except Exception as e: + print(e) + return False + +class ProxyServer: + input_list: list[Any] = [] + channel: dict[Any, Any] = {} + clients: list[list[Any]] = [] + forward_to: list[str | int] = [] + perms: list[PermType] = [] + + def __init__(self, remoteHost: str, remotePort: int, portManager: PortManager, perms: list[PermType]) -> None: + self.pm: PortManager = portManager + self.forward_to = [remoteHost, remotePort] + self.perms = perms + self.server: socket.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.server.bind(('127.0.0.1', 0)) + self.server.listen(200) + self.pm.addLocalBinding(remoteHost, remotePort, self.server.getsockname()[1]) + self.input_list.append(self.server) + + def main_loop(self) -> None: + ss = select.select + inputready, outputready, exceptready = ss(self.input_list, [], []) + for self.s in inputready: + if self.s == self.server: + self.on_accept() + break + + try: + self.data = self.s.recv(buffer_size) + if len(self.data) == 0: + self.on_close() + break + else: + self.on_recv() + except socket.error as e: + self.on_close() + + def on_accept(self) -> None: + clientsock, clientaddr = self.server.accept() + + if allowedIP(clientaddr[0], self.perms): + forward = Forward().start(self.forward_to[0], self.forward_to[1]) # type: ignore + if forward: + self.clients.append([clientaddr,clientsock,forward]) + self.pm.addClient(clientaddr) + self.input_list.append(clientsock) + self.input_list.append(forward) + self.channel[clientsock] = forward + self.channel[forward] = clientsock + else: + print("Can't establish connection with remote server.") + print("Closing connection with client side", clientaddr) + clientsock.close() + else: + print("Forbidden client IP") + clientsock.close() + + def on_close(self) -> None: + #remove objects from input_list + self.input_list.remove(self.s) + self.input_list.remove(self.channel[self.s]) + out = self.channel[self.s] + # close the connection with client + self.channel[out].close() # equivalent to do self.s.close() + # close the connection with remote server + self.channel[self.s].close() + # delete both objects from channel dict + del self.channel[out] + del self.channel[self.s] + + for c in self.clients: + if c[1] == self.s: + break + self.clients.remove(c) + self.pm.removeClient(c[0]) + + def on_recv(self) -> None: + data = self.data + # here we can parse and/or modify the data before send forward + self.channel[self.s].send(data) + for c in self.clients: + if c[1] == self.s: + self.parseData(data, c) + break + + def parseData(self, data: bytes, client: list[Any]) -> None: + for line in data.splitlines(): + lineSplit = line.decode().split(':', 1) + if lineSplit[0] == "Transport": + for transportOpt in lineSplit[1].split(';'): + if transportOpt.split('=')[0] == "client_port": + askedPorts = transportOpt.split('=')[1].split('-') + allowedPorts = [] + for port in askedPorts: + if allowedPortForward(client[0][0], port, self.perms): + allowedPorts.append(port) + self.pm.updatePorts(client[0], allowedPorts) + +class PortManager: + forwardedPorts: dict[Any, list[str]] = {} + localBindings: list[list[str | int]] = [] + allowedNets: list[str] = [] + + def __init__(self, perms: list[list[str]]) -> None: + for perm in perms: + network = perm[0] + self.allowedNets.append(network) + self.removeAll() + self.applyRules() + + def addClient(self, client: Any) -> None: + self.forwardedPorts[client] = [] + + def updatePorts(self, client: Any, ports: list[str]) -> None: + print("Forwarding ports for client " + client[0] + ". New list of ports is: {0}".format(ports)) + self.forwardedPorts[client] = ports + self.applyRules() + + + def removeClient(self, client: Any) -> None: + print("Remove client: " + client[0]) + self.forwardedPorts.pop(client) + self.applyRules() + + def removeAll(self) -> None: + f = open('/tmp/rtsphelper.rules', 'w') + f.close() + subprocess.call(['pfctl', '-a', 'rtsphelper', '-F', 'nat'], stdout=FNULL, stderr=subprocess.STDOUT) + subprocess.call(['pfctl', '-a', 'rtsphelper', '-F', 'rules'], stdout=FNULL, stderr=subprocess.STDOUT) + subprocess.call(['pfctl', '-a', 'rtsphelper', '-F', 'state'], stdout=FNULL, stderr=subprocess.STDOUT) + + def addLocalBinding(self, ip: str, port: int, local_port: int) -> None: + self.localBindings.append([ip, port, local_port]) + self.applyRules() + + def applyRules(self) -> None: + config_rule_1 = 'rdr inet proto tcp from any to {} port {} -> {} port {}\n' + config_rule_2 = 'block in quick on {} proto tcp from any to {} port {}\n' + config_rule_3 = 'pass in quick proto tcp from {} to {} port {}\n' + + pass_rule = 'pass in quick on {} inet proto udp from any to {} port {} keep state label "{}"\n' + rdr_rule = 'rdr on {} inet proto udp from any to any port {} -> {}\n' + + f = open('/tmp/rtsphelper.rules', 'w') + + for localBinding in self.localBindings: + f.write(config_rule_1.format(localBinding[0], localBinding[1], '127.0.0.1', localBinding[2])) + + for client,ports in self.forwardedPorts.items(): + ip = client[0] + for port in ports: + f.write(rdr_rule.format(config['ext_if'], port, ip)) + + f.write('\n') + for localBinding in self.localBindings: + f.write(config_rule_2.format(config['ext_if'], '127.0.0.1', localBinding[2])) + for network in self.allowedNets: + f.write(config_rule_3.format(network, '127.0.0.1', localBinding[2])) + + for client,ports in self.forwardedPorts.items(): + ip = client[0] + for port in ports: + f.write(pass_rule.format(config['ext_if'], ip, port, 'RTSP')) + + f.close() + subprocess.call(['pfctl', '-a', 'rtsphelper', '-f', '/tmp/rtsphelper.rules'], stdout=FNULL) + + +def writePidFile() -> None: + pid = str(os.getpid()) + f = open('/var/run/rtsphelper.pid', 'w') + f.write(pid) + f.close() + +def ip_to_u32(ip: str) -> int: + return int(''.join('%02x' % int(d) for d in ip.split('.')), 16) + +def allowedIP(ipstr: str, perms: list[PermType]) -> bool: + ip = ip_to_u32(ipstr) + for perm in perms: + mask, net = perm[0] + if ip & mask == net: + return True + return False + +def allowedPortForward(ipstr: str, port: str, perms: list[PermType]) -> bool: + if not allowedIP(ipstr, perms): + return False + else: + ip = ip_to_u32(ipstr) + for perm in perms: + mask, net = perm[0] + ports = perm[1] + if ip & mask == net: + if int(port) >= int(ports[0]) and int(port) <= int(ports[1]): + return True + return False + +def buildPerms(perms: list[list[str]]) -> list[PermType]: + masks: list[PermType] = [] + for perm in perms: + cidr = perm[0] + portRange = perm[1] + if '/' in cidr: + netstr, bits = cidr.split('/') + mask: int = (0xffffffff << (32 - int(bits))) & 0xffffffff + net: int = ip_to_u32(netstr) & mask + else: + mask = 0xffffffff + net = ip_to_u32(cidr) + masks.append(((mask, net), (min(portRange.split('-')[0],portRange.split('-')[1]),max(portRange.split('-')[0],portRange.split('-')[1])))) + return masks + +if __name__ == '__main__': + writePidFile() + + config['forward_to'] = [] + config['perms'] = [] + + with open(config_file, 'r') as cf: + line = cf.readline() + while line: + key,value = line.strip().split('=') + if key == 'ext_ifname': + config['ext_if'] = value + elif key == 'forward': + config['forward_to'].append([value.split(':')[0],int(value.split(':')[1])]) + elif key == 'allow': + config['perms'].append(value.split(' ')) + + line = cf.readline() + + perms = buildPerms(config['perms']) + servers: list[ProxyServer] = [] + + pm = PortManager(config['perms']) + + for forward in config['forward_to']: + servers.append(ProxyServer(forward[0], forward[1], pm, perms)) + + def handle_exit_signal(sig: int, frame: Any) -> None: + handle_exit() + + def handle_exit() -> None: + print("Exiting...") + pm.removeAll() + sys.exit(0) + + signal.signal(signal.SIGTERM, handle_exit_signal) + try: + while 1: + time.sleep(delay) + for server in servers: + server.main_loop() + except KeyboardInterrupt: + print("Ctrl C - Stopping server") + handle_exit() +sys.exit(1) \ No newline at end of file diff --git a/net/rtsphelper/src/opnsense/service/conf/actions.d/actions_rtsphelper.conf b/net/rtsphelper/src/opnsense/service/conf/actions.d/actions_rtsphelper.conf new file mode 100644 index 0000000000..6ab718290f --- /dev/null +++ b/net/rtsphelper/src/opnsense/service/conf/actions.d/actions_rtsphelper.conf @@ -0,0 +1,29 @@ +[start] +command:/usr/local/bin/python3 /usr/local/opnsense/scripts/net/rtsphelper/rtsphelper.py +type:script +message:starting rtsphelper + +[stop] +command:kill -TERM $(cat /var/run/rtsphelper.pid) 2> /dev/null; /sbin/pfctl -artsphelper -Fr 2> /dev/null; /sbin/pfctl -artsphelper -Fn 2> /dev/null; exit 0 +type:script +message:stopping rtsphelper + +[restart] +command:kill -TERM $(cat /var/run/rtsphelper.pid) 2> /dev/null; /sbin/pfctl -artsphelper -Fr 2> /dev/null; /sbin/pfctl -artsphelper -Fn 2> /dev/null; /usr/local/bin/python3 /usr/local/opnsense/scripts/net/rtsphelper/rtsphelper.py +type:script +message:restarting rtsphelper + +[status] +command:if [ -f /var/run/rtsphelper.pid ] && pgrep -F /var/run/rtsphelper.pid > /dev/null; then echo "running"; else echo "stopped"; fi +type:script_output +message:get rtsphelper status + +[connections] +command:/sbin/pfctl -artsphelper -sn 2> /dev/null +type:script_output +message:list rtsphelper connections + +[configure] +command:/usr/local/bin/php /usr/local/opnsense/scripts/net/rtsphelper/configure.php +type:script +message:configuring rtsphelper diff --git a/net/rtsphelper/src/www/services_rtsphelper.php b/net/rtsphelper/src/www/services_rtsphelper.php new file mode 100644 index 0000000000..2c5b12c355 --- /dev/null +++ b/net/rtsphelper/src/www/services_rtsphelper.php @@ -0,0 +1,279 @@ + 32) { + return false; + } + } elseif (count($ip_array) != 1) { + return false; + } + + /* validate ip */ + if (!is_ipaddr($ip_array[0])) { + return false; + } + + return true; +} + +function rtsphelper_validate_forward($forward) +{ + $fw_array = array(); + $fw_array = explode(':', $forward); + + if (!is_ipaddr($fw_array[0])) { + return false; + } + + $sub = $fw_array[1]; + if ($sub < 0 || $sub > 65535 || !is_numeric($sub)) { + return false; + } + + return true; +} + +function rtsphelper_validate_port($port) +{ + foreach (explode('-', $port) as $sub) { + if ($sub < 0 || $sub > 65535 || !is_numeric($sub)) { + return false; + } + } + + return true; +} + +if ($_SERVER['REQUEST_METHOD'] === 'GET') { + $pconfig = array(); + + $copy_fields = array('enable', 'ext_iface'); + + foreach (rtsphelper_permuser_list() as $permuser) { + $copy_fields[] = $permuser; + } + + foreach (rtsphelper_forward_list() as $forward) { + $copy_fields[] = $forward; + } + + foreach ($copy_fields as $fieldname) { + if (isset($config['installedpackages']['rtsphelper']['config'][0][$fieldname])) { + $pconfig[$fieldname] = $config['installedpackages']['rtsphelper']['config'][0][$fieldname]; + } + } +} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { + $input_errors = array(); + $pconfig = $_POST; + + /* user permissions validation */ + foreach (rtsphelper_permuser_list() as $i => $permuser) { + if (!empty($pconfig[$permuser])) { + $perm = explode(' ', $pconfig[$permuser]); + /* should explode to 2 args */ + if (count($perm) != 2) { + $input_errors[] = sprintf(gettext("You must follow the specified format in the 'User specified permissions %s' field"), $i); + } else { + /* verify port or port range */ + if (!rtsphelper_validate_port($perm[1]) ) { + $input_errors[] = sprintf(gettext("You must specify a port or port range between 0 and 65535 in the 'User specified permissions %s' field"), $i); + } + /* verify ip address */ + if (!rtsphelper_validate_ip($perm[0])) { + $input_errors[] = sprintf(gettext("You must specify a valid ip address in the 'User specified permissions %s' field"), $i); + } + } + } + } + + foreach (rtsphelper_forward_list() as $i => $forward) { + if (!empty($pconfig[$forward])) { + if (!rtsphelper_validate_forward($pconfig[$forward])) { + $input_errors[] = sprintf(gettext("You must specify a valid ip and port in the 'Hosts to enable %s' field"), $i); + } + } + } + + if (count($input_errors) == 0) { + // save form data + $rtsp = array(); + // boolean types + foreach (array('enable') as $fieldname) { + $rtsp[$fieldname] = !empty($pconfig[$fieldname]); + } + // text field types + foreach (array('ext_iface') as $fieldname) { + $rtsp[$fieldname] = $pconfig[$fieldname]; + } + foreach (rtsphelper_permuser_list() as $fieldname) { + $rtsp[$fieldname] = $pconfig[$fieldname]; + } + foreach (rtsphelper_forward_list() as $forward) { + $rtsp[$forward] = $pconfig[$forward]; + } + // sync to config + $config['installedpackages']['rtsphelper']['config'] = $rtsp; + + write_config('Modified RTSP Helper settings'); + rtsphelper_configure_do(); + filter_configure(); + header(url_safe('Location: /services_rtsphelper.php')); + exit; + } +} + + +$service_hook = 'rtsphelper'; +legacy_html_escape_form_data($pconfig); +include("head.inc"); +?> + + +
+
+
+ 0) print_input_errors($input_errors); ?> +
+
+
+
+ + + + + + + + + + + + + + + + + +
+ + + + +    +
+ /> +
+ + +
+
+
+
+
+
+
+ + + + + + + + $forward): ?> + + + + + + + + + + +
+ + + + +
+
+
+
+
+
+
+ + + + + + + + $permuser): ?> + + + + + + + + + + +
+ + + + +
+
+
+
+
+
+
+ + + + + + + +
  + " /> +
+
+
+
+
+
+
+
+ diff --git a/net/rtsphelper/src/www/status_rtsphelper.php b/net/rtsphelper/src/www/status_rtsphelper.php new file mode 100644 index 0000000000..76e5c5c39c --- /dev/null +++ b/net/rtsphelper/src/www/status_rtsphelper.php @@ -0,0 +1,80 @@ + + + + +
+
+
+
+
+ +
+

+
+ +
+ + + + + + + + + (.*)/", $rdr_entry, $matches)) { + continue; + } + $rdr_ip = $matches[6]; + $rdr_iport = $matches[5]; + ?> + + + + + + + + + + + +
+
+ + . +
+
+
+ +
+
+
+
+
+