📜 ⬆️ ⬇️

Udpxy on the provider's server

The remarkable utility udpxy has two features that need to be considered when using it in the carrier’s network.

First of all, the status and reset commands are available to all clients via the Web browser.

Secondly, at about 40 simultaneous threads, udpxy starts to slow down, although the processor and the network interface are practically not occupied.
')

Small retreat


As a rule, udpxy is not in the form of a binary package under the desired distribution, so it must be collected from the source code.

Clogging the working system with packages necessary for building (compilers, libraries, utilities) is a bad practice - the size of updates increases, dependencies become more complex, etc.

On the other hand, the organization of a separate assembly farm complicates the assembly, since requires synchronization of working and build software versions, explicitly specifying some parameters instead of automatic detection, transfer of assembled packages, etc.

A compromise for a one-time build is to create a temporary build environment (sandboxes, aka sandboxes) on a working system in a separate directory.

In Debian Squeeze, the following commands are enough:
apt-get install debootstrap mkdir /home/builder debootstrap squeeze /home/builder http://mirror.yandex.ru/debian chroot /home/builder apt-get update chroot /home/builder apt-get -y dist-upgrade chroot /home/builder apt-get -y install gcc make 

To build udpxy, only gcc and make are needed, for larger programs, the required packages may be larger.

Assembly and installation


Download the archive with the source code and deploy in a sandbox:
 ver="1.0.23-0" wget http://downloads.sourceforge.net/project/udpxy/udpxy/Chipmunk-1.0/udpxy.${ver}-prod.tar.gz' tar xzf ~/udpxy.${ver}-prod.tar.gz -C /home/builder/home/ 

Change the names of control commands to very secret:
 cd /home/builder/home/udpxy-${ver} sed -i.orig -e 's!/restart!/SECRET_restart!' -e 's!/status!/SECRET_status!' statpg.h sed -i.orig -e 's!"status"!"SECRET_status"!' -e 's!"restart"!"SECRET_restart"!' -e 's!"rtp"!"SECRET_rtp"!' extrn.c 

Go to the sandbox and compile:
 chroot /home/builder make -C /home/udpxy-${ver} 

Create a pseudo-user to run udpxy and a directory for the program and utilities, transfer the program to it:
 useradd --system --shell /bin/true --create-home udpxy install -o udpxy -g udpxy -m 700 -p /home/builder/home/udpxy-${ver}/udpxy /home/udpxy/ 


Launch


To increase the working limit of simultaneous connections, we will run several udpxy instances on different ports and scatter requests coming to the standard port 4022, depending on the client’s IP address using iptables => nat => PREROUTING => REDIRECT:
 #!/bin/bash # /home/udpxy/start MAINPORT="4022" SUBPORTS="16" SUBMASK="40%02d" LOGDIR="/var/log/udpxy" UDPXY="/home/udpxy/udpxy" USER="udpxy" mkdir -p $LOGDIR || { echo "ERROR: cannot create $LOGDIR, aborted."; exit 1; } id "$USER" > /dev/null 2>&1 || { echo "ERROR: user $USER does not exists, aborted."; exit 1; } # Run instances and create redirects... for ((a = 0; a < "$SUBPORTS"; a++)); do p=`printf "$SUBMASK" "$a"` iptables -t nat -I PREROUTING -s 0.0.0.0/0.0.0.$a -p tcp -m tcp --dport "$MAINPORT" \ -j REDIRECT --to-ports "$p" while : ; do date +"%Y.%m.%d %H:%M:%S -- Started $p" sudo -u "$USER" "$UDPXY" -T -p $p -c32 date +"%Y.%m.%d %H:%M:%S -- Finished $p" sleep 30 done >> "$LOGDIR/$p.log" 2>&1 & done 

Explanations: First, the script requires bash, because sh does not understand the loop with the counter. Secondly, you cannot use “iptables -A” instead of “-I”, since the rule with "-s 0.0.0.0/0.0.0.0" will be the first and take all the connections. Third, the script continues to run in the background and automatically restarts completed (dropped?) Instances of udpxy.

By default, udpxy displays minimum information in the /var/log/udpxy/*.log log files. If you need to make the output more detailed, add the "-v" and "-S" switches to the "sudo -u ..." startup line.

Additional handles for which it makes sense to twist: "-B 1Mb" to increase the input buffer (in bytes), "-R 10" - the simultaneous number of messages (in pieces) and "-H 5" - the maximum data buffering time (in seconds ).

Add a call to / home / udpxy / start in /etc/rc.local (we will postpone the writing of scripts for /etc/init.d for another time).

The completion script should look something like this:
 #!/bin/bash # /home/udpxy/stop # Remove firewall rules... iptables-save \ | grep -- "-p tcp -m tcp --dport 4022 -j REDIRECT --to-ports" \ | sed 's/^-A/iptables -t nat -D/' \ | sh - # Kill program instances... pkill -f "/home/udpxy/udpxy" sleep 5 # Kill wrapper scripts... pkill -f "/home/udpxy/start" 


View status


You can view a general list of connections to all udpxy instances as follows:
 #!/usr/bin/perl # /var/www/html/SECRET-udpxy-status.cgi use strict; use warnings; my $port0 = 4000; my $ports = 16; my $status_cmd = 'SECRET_status'; my $title = "Udpxy summary status"; my $hostname; ($hostname = $ENV{HTTP_HOST}) =~ s/:\d+$//; print "Content-type: text/html\n\n" if $ENV{REMOTE_ADDR}; # ..cgi-bin mode? print << "__HEAD__"; <html> <head> <title>$title</title> </head> <body> <div id='bodyCon'> <h1>$title</h1> <div id='pgCont'> <table border='1'> <tr><th>Port</th><th>Process ID</th><th>Source</th><th>Destination</th><th>Throughput</th></tr> __HEAD__ my %cnt; my $total = 0; my $style_copied; my $style_passed; for (my $p = $port0; $p < $port0 + $ports; $p++) { open F, "wget -q -O - http://localhost:$p/$status_cmd |"; while(<F>) { if ($style_copied and /<\/style>/) { $style_copied = 0; # ..style finished $style_passed = 1; print; } elsif (/<style/ and not $style_passed) { $style_copied = 1; # ..style started print; } elsif ($style_copied) { # ..style copy in progress print; } elsif (/<td>\d+<\/td><td>\d+\.\d+\.\d+\.\d+:\d+<\/td>/) { s/<tr([^>]*)>/<tr$1><td>$p<\/td>/; # ..insert first column with port number ($cnt{$p} ||= 0)++; $total++; print; } } close F; } print "</table><h3>Clients count</h3><table border='1'><tr><th>Port</th>\n"; print "<td><a href='http://$hostname:$_/$status_cmd'>$_</a></td>\n" foreach $port0 .. ($port0 + $ports - 1); print "<th>Total</th></tr><tr><th>Count</th>\n"; printf "<td>%s</td>\n", $cnt{$_} || '' foreach $port0 .. ($port0 + $ports - 1); print "<th>$total</th></tr></table></div></div></body></html>\n"; 

Perhaps there is a simpler way, but this one turned out to be the fastest.

You can run it from under any Web server with CGI-BIN support. In Debian, mini-httpd is perfect for this:
 apt-get install mini-httpd echo 'START=1' >> /etc/default/mini-httpd echo ' port=4020 user=nobody nochroot dir=/var/www data_dir=/var/www/html cgipat=**.cgi logfile=/var/log/mini-httpd.log pidfile=/var/run/mini-httpd.pid charset=utf-8 ' > /etc/mini-httpd.conf /etc/init.d/mini-httpd restart 


SNMP


To view via SNMP in Cacti / Zabbix / MRTG the current number of connected clients (maximum per process + total), add to /etc/snmp/snmpd.conf:
 exec udpxy_connections /etc/snmp/udpxy_connections.sh 

Actually /etc/snmp/udpxy_connections.sh script:
 #!/bin/sh A() { netstat -nt |grep ESTABLISHED |grep -v 127.0.0.1: |awk '{print $4;}' |egrep ':40[01][0-9]$'; } A | wc -l A | awk -F : '{print $2;}' | sort | uniq -c | sort -nr | head -1 | awk '{print $1;}' 

Check:
 snmpwalk -On -c SecretCommunity -v2c 10.20.30.40 NET-SNMP-EXTEND-MIB::nsExtendObjects 


Conclusion



Unfortunately, not every old network can be upgraded (replacing stupid ones with controllers, replacing garlands with straight fibers, etc.) required for the normal operation of IP television via multicast can be made quickly. The temporary option with udpxy allows you to start the IPTV service, without waiting for the network to be brought up to date.

Source: https://habr.com/ru/post/152397/


All Articles