Categories: Linux

Testing if socket is accepting connections

nmap and netcat are great and easy ways to test if a socket is open and accepting connections:

Using netcat

 nc -zv www.example.com 80
Connection to www.example.com 80 port [tcp/http] succeeded!

Using nmap

 nmap -v example.com -Pn -p 80
Starting Nmap 7.80 ( https://nmap.org ) at 2021-03-02 06:23 CST
Initiating Parallel DNS resolution of 1 host. at 06:23
Completed Parallel DNS resolution of 1 host. at 06:23, 0.17s elapsed
Initiating Connect Scan at 06:23
Scanning example.com (93.184.216.34) [1 port]
Discovered open port 80/tcp on 93.184.216.34
Completed Connect Scan at 06:23, 0.06s elapsed (1 total ports)
Nmap scan report for example.com (93.184.216.34)
Host is up (0.062s latency).
Other addresses for example.com (not scanned): 2606:2800:220:1:248:1893:25c8:1946

PORT   STATE SERVICE
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.36 seconds

ncat and nmap may not always be installed, also the telnet package is usually no longer installed by default in most distributions.

These are some simple alternatives I have found useful to test connectivity:

Using openssl, the timeout is long and not configurable, but it does clearly state when able to open a socket with a message saying CONNECTED

openssl s_client -connect www.example.com:80
CONNECTED(00000003)
139935405417792:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:331:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 306 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---

You can also use the following simple python2 script to test if a port is accepting connection, the script takes two arguments host and port.

import socket
import sys

def test_socket(ip,port):
    s = socket.socket()
    try:
        s.settimeout(3)
        s.connect((ip,port))
    except socket.error as msg:
        s.close()
        print 'could not open %s:%s %s' % (ip,port,msg)
        return(1)
    else:
        s.close()
        print '%s:%s is OK' % (ip,port)
        return(0)

test_socket(sys.argv[1],int(sys.argv[2])) 

The script returns OK if its able to accept a connection

python test_socket.py www.example.com 80
www.example.com:80 is OK

Or returns the socket.error instead

python test_socket.py www.example.com 81
could not open www.example.com:81 timed out
 python test_socket.py localhost 81
could not open localhost:81 [Errno 111] Connection refused

Categories: Docker, Linux

Using syslog to log Docker containers

TL DR; If you need to setup syslog for your docker container here is a great example.

Docker supports using syslog protocol to capture the logs of the containers.

I found this example amazing. However when trying to implement it, faced some issues with the rsyslog regex notation. Also I found some applications do not have a timestamp if I want to add a timestamp, I pass a tag ‘add_timestamp’

In the end here is what I used:

Created a docker directory /var/log/docker and a container log directory /var/log/docker/container

sudo mkdir /var/log/docker
sudo mkdir /var/log/docker/container

Created the following rsyslog config /etc/rsyslog.d/docker.conf

$template DockerLogs, "/var/log/docker/daemon.log"
if $programname startswith 'dockerd' then -?DockerLogs
& stop

$template ContainerLog,"/var/log/docker/container/%syslogtag:R,ERE,1,FIELD:container_(\w*)--end%.log"
$template ContainerLogFormat, "%msg:::sp-if-no-1st-sp%%msg:::space-cc,drop-last-lf%\n"
$template ContainerLogFormatTimestamp, "%TIMESTAMP:::date-rfc3339% %msg:::sp-if-no-1st-sp%%msg:::space-cc,drop-last-lf%\n"

if $syslogtag contains  'add_timestamp' then ?ContainerLog;ContainerLogFormatTimestamp
else if $syslogtag contains  'container_' then ?ContainerLog;ContainerLogFormat
& stop

Configured /etc/docker/daemon.json with the log-driver and options to use as default (You need to create daemon.json it if it does not exist)

{
"log-driver":"syslog",
"log-opts": {
    "tag":"container_{{.Name}}"
 }
}

For the logs that need a timestamp we pass the add_timestamp tag when running them i.e:

docker run -d  --log-opt tag="container_{{.Name}}/add_timestamp" container_image_name

Categories: Docker, Linux

WordPress + Docker + Cloudfare

TLDR; Sign-up and host your blog with WordPress

I just took the task of renewing my blog, WordPress is awesome, I found they maitain their own docker image: https://hub.docker.com/_/wordpress

I already had a db server running, and setting their docker container with my existing db was super easy. To get things running I just had to do this:

docker run -d \
  --name=wordpress\
  -p 80:80 \
  -v /some_directory/wp-content/:/var/www/html/wp-content\
  -e WORDPRESS_DB_HOST=mysqlhost.example.com \
  -e WORDPRESS_DB_USER=my_wp_db_user \
  -e WORDPRESS_DB_PASSWORD=my_wp_db_pass \
  -e WORDPRESS_DB_NAME=my_wp_name \
  wordpress

I am also using Cloudflare which is an awesome service, they act as a proxy between the world and my humble box running the wordpress docker container. The WordPress container comes with mod_remote_ip preconfigured

Cloudflare provided the following instructions for setting up mod_remoteip the wordpress container already has remoteip.conf pre-configured with these nice config:

RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 10.0.0.0/8
RemoteIPTrustedProxy 172.16.0.0/12
RemoteIPTrustedProxy 192.168.0.0/16
RemoteIPTrustedProxy 169.254.0.0/16
RemoteIPTrustedProxy 127.0.0.0/8

So I only had to append this section to the existing configuration file: /etc/apache2/conf-available/remoteip.conf

RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 173.245.48.0/20
RemoteIPTrustedProxy 103.21.244.0/22
RemoteIPTrustedProxy 103.22.200.0/22
RemoteIPTrustedProxy 103.31.4.0/22
RemoteIPTrustedProxy 141.101.64.0/18
RemoteIPTrustedProxy 108.162.192.0/18
RemoteIPTrustedProxy 190.93.240.0/20
RemoteIPTrustedProxy 188.114.96.0/20
RemoteIPTrustedProxy 197.234.240.0/22
RemoteIPTrustedProxy 198.41.128.0/17
RemoteIPTrustedProxy 162.158.0.0/15
RemoteIPTrustedProxy 104.16.0.0/12
RemoteIPTrustedProxy 172.64.0.0/13
RemoteIPTrustedProxy 131.0.72.0/22
RemoteIPTrustedProxy 2400:cb00::/32
RemoteIPTrustedProxy 2606:4700::/32
RemoteIPTrustedProxy 2803:f800::/32
RemoteIPTrustedProxy 2405:b500::/32
RemoteIPTrustedProxy 2405:8100::/32
RemoteIPTrustedProxy 2a06:98c0::/29
RemoteIPTrustedProxy 2c0f:f248::/32

I am not yet running in swarm mode, so I am not using the config option.
I am just configuring it before starting the container. i.e:

  1. Create the WP container
docker create \
  --name=wordpress\
  -p 80:80 \
  -v /some_directory/wp-content/:/var/www/html/wp-content\
  -e WORDPRESS_DB_HOST=mysqlhost.example.com \
  -e WORDPRESS_DB_USER=my_wp_db_user \
  -e WORDPRESS_DB_PASSWORD=my_wp_db_pass \
  -e WORDPRESS_DB_NAME=my_wp_name \
  wordpress

2. Copy my modified config file with the original content plus the Cloudflare IPs and header

docker cp /some_directory/remoteip.conf wordpress:/etc/apache2/conf-available/remoteip.conf

3. Start the container

docker start wordpress

Categories: Blog, Linux

WordPress Upgrade 4.3 breaks wordpress cron wp-cron.php

There is a fresh bug in WordPress 4.3, it will cause a race condition in the wordpress cron, and the contents option_value of the option_name cron in wp_options will continue growing.

It will continue growing unchecked, this caused our binary log to fill up the disk.

You can check the size of the cron with:


mysql> select option_name,length(option_value) from wp_options where option_name ='cron';

If it continues growing unchecked you have hit the bug.
 
Here is the mailing list discussion of the bug:
http://lists.automattic.com/pipermail/wp-trac/2015-August/265144.html
 
Here is the changelist with the fixes for this bug
https://core.trac.wordpress.org/changeset/33647
 
If after applying the patch the old crontasks don’t get executed you may need to clear the cron:

mysql> UPDATE wp_options SET option_value = '' WHERE option_name = 'cron';


Starting mysqld and httpd on demand with xinetd

My father gave me an awesome present besides life 🙂
He gave me a Raspberry Pi B model, its basically a low power consumption, low spec computer board, at a very low price intended for tinkerers, and electronic education.

I am using it to host my own PBX which is based of this project: Asterisk for raspberry
I am also using it for other purposes such as monitoring my home network as an active IDS, a dns server, a proxy, a vpn server, basically I want to use it for all the things you always wanted to have on a always-on server inside your house.

The problem I encountered was that the Pi model B comes with only 512 mb of RAM, and the Freepbx software uses Apache PHP5 and Mysql which consumes a good amount of RAM.
First step was easy, I just installed lighttpd and stopped apache. Second step I started looking into changing Freepbx to a SQLite engine, to get rid of MySQL, but Freepbx support for it was not 100%.

So after looking for a while I found a very nice solution for all my troubles, using xinetd and netcat (awesome tools) I start services on demand, when a connection comes in I start the required service and leave a background process to check on if the service is still required, if the port sees no further activity the service gets shutdown. So I can now have all the services that I want on the resource limited device.

I struggled to find how to do this. So I am sharing how I did it. I am also basing myself of this great post which does something similar but with another purpose in mind. Automatic Tunnels with xinetd and netcat.

Tools required:

This is my startup script I created here /etc/xinetd.init.d/lighttpd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/bin/bash
# inspired on this article
# https://www.linuxnet.ch/automatic-tunnels-with-xinetd-and-netcat/
# script is called from xinetd
# script starts and stops service using /etc/init.d scripts
 
SERVICE=/etc/init.d/lighttpd  # script used to start/stop service
PORT=81 # port where end service should listen
PID_FILE=/var/run/lighttpd.pid # pid file generated by init script
REAPER_PID_FILE="/var/run/lighttpd_reaper.pid" # pid file generated by this script
REAPER_SLEEP=180 # The reaper sleeps in seconds and checks for idle conns
LOG=/var/log/syslog # where to log messages
 
# this function checks if we already have reaper
check_reaper(){
        if  [ -s $REAPER_PID_FILE ]
        then
                reaper_pid=`cat $REAPER_PID_FILE 2>/dev/null`
                ps -p $reaper_pid &> /dev/null
                if [ $? -ne 0 ]
                then
                        start_reaper &    # If we dont have a reaper we start one
                        echo $! > $REAPER_PID_FILE
                fi
        else
                start_reaper &
                echo $! > $REAPER_PID_FILE
        fi
 
}
 
# this function starts a reaper, which is a background process that will kill the end service if its inactive
start_reaper(){
        while [ -f $PID_FILE ]
        do
                sleep $REAPER_SLEEP                                      # We wait
                touched=`stat --printf %W $REAPER_PID_FILE 2>/dev/null`  # We check when the reaper PID was last touched
                now=`date +%s 2>/dev/null`
                let idle=$now-$touched
                if [ $idle -gt $REAPER_SLEEP ]              # If reaper pid has not been touched in more than a sleep cycle we stop the service
                then
                        echo `date`" REAPER STOPPING SERVICE AFTER BEING $idle" >> $LOG   
                        $SERVICE stop >> $LOG               # This is the stop service instruction
                        rm $REAPER_PID_FILE 
                        exit 0
                fi
        done
}
 
# This is where we start our service
start_service(){
        sleep 1                    # Added a delay to trouble shoot as browsers kickstart several connections, we need to allow the PID file to be created this can be improved.
        if [ -s $PID_FILE ]        # We check if the PID file for the end service exist to avoid calling the start script when the service has already been started
        then
                return
        else
                echo `date`" STARTING $SERVICE" >> $LOG
                $SERVICE start &>> $LOG                  #this is the start service instruction
                return
        fi
}
 
# We probe and wait for the service to come on line
wait_for_service(){
        nc -w30 -z 127.0.0.1 $PORT &>/dev/null          # probe end port with a timeout of 30 seconds
        if [[ $? -ne 0 ]]
        then
                echo `date`" XINET SERVICE START ON $PORT TIMED OUT" >> $LOG
        fi
}
 
# This is were all the magic happens netcat passes traffic back and forth
transmit(){
        nc -w30 127.0.0.1 $PORT 2>/dev/null  # netcat is awesome, timeout flag of 30 seconds can be adjusted
}
 
# this is the main program that is called every time
main()
{
        nc -z 127.0.0.1 $PORT &>/dev/null  # We probe the end service
        if [[ $? -ne 0 ]]                  # If its not responding
        then
                start_service              # We start service
                wait_for_service           # We wait for service to became online
        fi
        check_reaper                       # We always check we have a reaper
        touch $REAPER_PID_FILE             # We log activity by touching the reaper PID file
        transmit                           # We transmit data 
        exit 0                             
}
 
main

This is the configuration for xinet.d

1
2
3
4
5
6
7
8
9
10
service http
{
        disable         = no
        socket_type     = stream
        protocol        = tcp
        port              = 80
        server = /etc/xinetd.init.d/lighttpd
        user            = root
        wait            = no
}

For mysqld I did something similar but I had to add a wait time as mysql takes longer to boot
mysql startup script I placed it in /etc/xinetd.init.d/mysqld
Another thing I encountered was that mysql clients tend to default to use the socket file, so I had to reconfigure so it would listen on the eth0 address, as a precaution I added a rule to only allow the same IP to access it, I can probably improve this too but I got it working like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/bin/bash
# inspired on this article
# https://www.linuxnet.ch/automatic-tunnels-with-xinetd-and-netcat/
 
SERVICE=/etc/init.d/mysql
PORT=3307
PID_FILE=/var/run/mysqld/mysqld.pid
REAPER_PID_FILE=/var/run/mysqld/mysqld_reaper.pid
REAPER_SLEEP=300
LOG=/var/log/syslog
IP='192.168.1.50'
 
check_reaper(){
        if  [ -s $REAPER_PID_FILE ]
        then
                reaper_pid=`cat $REAPER_PID_FILE 2>/dev/null`
                ps -p $reaper_pid &> /dev/null
                if [ $? -ne 0 ]
                then
                        start_reaper &
                        echo $! > $REAPER_PID_FILE
                fi
        else
                start_reaper &
                echo $! > $REAPER_PID_FILE
        fi
 
}
 
start_reaper(){
        while [ -f $PID_FILE ]
        do
                sleep $REAPER_SLEEP
                touched=`stat --printf %W $REAPER_PID_FILE 2>/dev/null`
                now=`date +%s 2>/dev/null`
                let idle=$now-$touched
                if [ $idle -gt $REAPER_SLEEP ]
                then
                        echo `date`" REAPER STOPPING SERVICE AFTER BEING $idle" >> $LOG
                        $SERVICE stop >> $LOG
                        rm $REAPER_PID_FILE
                        exit 0
                fi
        done
}
 
start_service(){
        if [ -s $PID_FILE ]
        then
                return
        else
                echo `date`" STARTING $SERVICE" >> $LOG
                $SERVICE start &>> $LOG
                return
        fi
}
 
wait_for_service(){
        sleep 10
        nc -w30 -z $IP $PORT &>/dev/null
        if [[ $? -ne 0 ]]
        then
                echo `date`" XINET SERVICE START ON $PORT TIMED OUT" >> $LOG
        fi
}
 
transmit(){
        nc -w30 $IP $PORT 2>/dev/null  # netcat is awesome
 
}
 
main()
{
        nc -z $IP $PORT &>/dev/null
        if [[ $? -ne 0 ]]
        then
                start_service &
                wait_for_service
        fi
        check_reaper &>/dev/null
        touch $REAPER_PID_FILE &>/dev/null
        transmit
        exit 0
}
 
main

And its xinet config file looks like this:
/etc/xinetd.d/mysqld

1
2
3
4
5
6
7
8
9
10
11
12
service mysql
{
        disable         = no
        type            = UNLISTED
        socket_type     = stream
        port              = 3306
        server = /etc/xinetd.init.d/mysqld
        user            = root
        wait            = no
        bind            = 192.168.1.50
        only_from       = 192.168.1.50
}

 

 


Categories: Linux

Telmex troncal SIP con Asterisk11

Como conectar una linea voip telmex a una troncal asterisk.


Categories: Python

Python vimrc

A nice tip if you work with python under vi, use this vimrc config file.

http://svn.python.org/projects/python/trunk/Misc/Vim/vimrc

you can just copy it to your home directory
wget http://svn.python.org/projects/python/trunk/Misc/Vim/vimrc ~/python_vimrc

you can start vi with vi -u ~/python_vimrc

Or make it your default .vimrc you will end with nice syntax highlighting


Nagios Acknowledge for the Masses

I made this simple perl script to help with the acknowledging of multiple alerts.

When running in a large environment, and during a large maintenance alerts can flood the user and even with the use aid of servicegroups and hostgroups the alerts can overwhelm the user.

The script lists any problem unacknowledged or without unscheduled downtime.
Similar to what this link does:

/cgi-bin/status.cgi?host=all&type=detail&servicestatustypes=29&hoststatustypes=15&serviceprops=10

To setup the script, make sure you edit the paths to your nagios status.dat, and the command FIFO file.
Script should be able to write to the FIFO file.

To use the script, run without arguments, in interactive mode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/usr/bin/perl
 
#####################################################################################################
#   This script provides help to acknowledge multiple services during a large maintenance
#   Sometimes host groups and service groups do not suffice
#      Script requires the setup of the location of the status.dat and the FIFO file
#      Script should be able to write to the FIFO file
#	Command is run interactively
#      Santiago Velasco - sanxiago.com
#########################################################################################
 
	my $command_file = "/usr/local/nagios/var/rw/nagios.cmd";
	my $status_file = "/usr/local/nagios/var/status.dat";
	my $time = time();
	my %state = (1 ,'WARNING', 2,'CRITICAL', 3,'UNKNOWN');
	my $user = $ARGV[0];
	my $msg = $ARGV[1];
	my $search_string = $ARGV[3];
 
print STDERR "nnACKNOWLEDGE AND SCHEDULE DOWNTIME FOR MULTIPLE SERVICESnn";
 
while(!defined($user) or $user =~ /;|[|]/  or length($user)<=1){
	print STDERR "Type in yout USER that acknowledges:n";
	$user = <>;
	$user =~ s/n//;
}
while (!defined($msg) or $msg =~ /;|[|]/ or length($msg)<=1 ){
	print STDERR "Type in the MESSAGE that will be used for all acknowledges:n";
	$msg = <>;
	$msg =~ s/n//;
}	
print STDERR "Type in a string that matches the service_description of the services you want to ack.n Leave it blank to list all alerts):n"; $search_string = <>; $search_string =~ s/n//; if(length($search_string)<=1){
	$search_string='.*';
}
 
if (-r $status_file){	
	open (STATUS, $status_file);
}
else {
	print STDERR "FAILED TO READ NAGIOS STATUS FILEn";
	exit 1;
}
while(<STATUS>){
	if($_ =~ /service {/){
	$is_service = 1;
	}
	if($_ =~ /}/ and $service_description=~/$search_string/){
	$is_service =0;
		if(defined($current_state) and $current_state and $acknowledged==0 and $scheduled_downtime==0 ){
		# Command Format:
		# [time] ACKNOWLEDGE_SVC_PROBLEM;<host_name>;<service_description>;<sticky>;<notify>;<persistent>;<author>;<comment>
		# [time] SCHEDULE_SVC_DOWNTIME;<host_name>;<service_desription><start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment>
 		undef($ack_true);
		print STDERR "n---------------------------------------------------------n";
		print STDERR "Acknowledge $service_description @ $host_name $current_state".$state{$current_state}."?n$plugin_outputn[y/n/s] (s followed by the number of minutes of scheduled downtime) (Enter to skip)n";
		$ack_true=<>;
		# if acknowledge yes
		if($ack_true=~/^y/){
			if (!(-w $command_file)){ print STDERR "FAILED TO OPEN FIFO FILE"; exit 1; }
			open (CMD, '>>'.$command_file);
			print CMD "[$time] ACKNOWLEDGE_SVC_PROBLEM;$host_name;$service_description;1;0;1;$user;$msgn";
			close (CMD);
		# if schedule downtime 
		}elsif($ack_true=~/^s(.*)/){
			my $duration = $1;
			if($duration=~/[^d]*([0-9]+).*/){
				#expect duration in minutes convert to seconds
				$duration=int($1)*60;
			}else{
				$duration=3600;
			}
                        my $end_time = $time + $duration;
 
                        if (!(-w $command_file)){ print STDERR "FAILED TO OPEN FIFO FILE"; exit 1; }
                        open (CMD, '>>'.$command_file);
			print CMD "[$time] SCHEDULE_SVC_DOWNTIME;$host_name;$service_description;$time;$end_time;1;0;$duration;$user;$msgn";
                        close (CMD);
		}
		}
	undef($current_state);
	undef($host_name);
	}
	if($is_service){
		if($_=~/host_name=(.*)/){
		$host_name=$1;
		}
		if($_=~/service_description=(.*)/){
		$service_description=$1;
		}
                if($_=~/current_state=([0-9]*)/){
                $current_state=$1;
                }
                if($_=~/problem_has_been_acknowledged=([0-9]*)/){
                $acknowledged=$1;
                }
                if($_=~/plugin_output=(.*)/){
                $plugin_output=$1;
                }
		if($_=~/scheduled_downtime_depth=([0-9]*)/){
		$scheduled_downtime=$1;
		}
	}
}
close(STATUS);

Categories: Python

Python object dump

When working with objects and arrays there are times you need to debug a certain object or array and list all its contents.
Most languages provide a functionality to do so, in the case of Perl you have Data::Dumper and in PHP you have print_r

I was looking for something like that and found:

Recipe

I truly recommend it.
It can be easily added as an extra module.


Categories: Blog

Bank decreases security in attempt to increase password strength

I was asked to set my phone password by my bank, following these rules:
1. Password must have 7 digits
2. No digits can repeat in a password
3. Consecutive digits are not allowed

Some security expert thought the best way to protect the “stupid” users from choosing easy passwords.
Was to enforce rules 2 and 3.
Lets keep in mind that without the rules 2 and 3 we had 9’999’999 possible passwords.

Rule 2 means you must pick 7 numbers out of the 9 digits without repeating any digit.
Using simple math we have
nPr = n! / (n-r)!
Were n is 9 as there are 9 digits in a phone, as r is 7 as that is the digits we must pick out.
We have: 9! / 2 = 181,440
As a result we have only 181,440 Valid passwords, this rule alone reduces the hackers guessing effort in a 98% Nicely Done!

*Rule 3, sequences of numbers are not allowed, this is the cherry on top.
NCm – ( N – m + 1 )Cm
We have: 6435 – 84 = 6351
Thats 6351 passwords we are unable to use.
181,440 – 6,351 = 175,089

It reduces even further the possibilities, this alone is not a bad rule, but since someone reduced the set most users will not be able to choose a password they can relate, so they are confined in this set, so my guess is most users ended up choosing a password based on the phone layout, as the rules above are too restrictive.

Look at the common phone digits layout:
1 2 3
4 5 6
7 8 9
    0

This are my guesses on the most common passwords:
1-4-7 2-5-8-0
3-6-9 2-5-8-0
2-5-8-0 1-4-7
2-5-8-0 3-6-9

* http://www.albaiges.com/matematicas/combinatoria/combinacionesordenadas.htm