Notes to self, 2009
2009-12-28 - mysql ubuntu readline delete-char / karmic
A couple of months ago, I wrote about how to get the delete key (and reverse history search) to work again on mysql-client-5.1 that comes with Ubuntu/Jaunty.
That trick doesn't work anymore with Ubuntu/Karmic and here's why:
As you can see from these highlighted
differences between mysql 5.1.31 and 5.1.37 (the versions used in Jaunty and Karmic
respectively), you can see that it previously tested for the issetugid(2)
syscall
but ignored it if it doesn't exist. At some point after 5.1.31 did the mysql guys change
that to returning early if the function doesn't exist.
This means that in Ubuntu/Karmic which doesn't have an issetugid function (availability
seems limited to BSD's and Solarises) the .editrc
file from the homedir will
not be read.
So.. how to fix this? There are three places where a committed fix will turn up in Karmic: (1) in the mysql source, (2) in the debian package, (3) in the ubuntu package. The fix itself is simple enough: emulate issetugid with syscalls that do exist. Google turns up plenty of examples where getuid is compared against geteuid and getgid is compared against getegid. If one of those doesn't match, issetugid returns nonzero (the value 1).
Something like this patch
should to the trick. I have it compiled into a nice ubuntu package (for amd64 only!):
mysql-client-5.1_5.1.37-1ubuntu5wjd1_amd64.deb
References:
Debian bug 552003:
debian mysql-client uses libedit instead of libreadline
MySQL bug 49967:
built-in libedit doesn't read .editrc on linux
Ubuntu bug 451801:
some keys like the delete-char do not work in mysql-client
Update 2009-12-29
For the ubuntu users, it's probably better to have the mysql-client linked
against libreadline6 — that's what the debian bug is about — instead of
to a fixed libedit. While we're waiting for the fix from upstream debian, I've compiled an ubuntu
package for that as well (again, for amd64 only!) with
these changes:
mysql-client-5.1_5.1.37-1ubuntu5wjd2_amd64.deb
Things to remember:
$ apt-cache source / showsrc ...
$ apt-get build-dep ...
$ dch -l wjd
$ DEB_BUILD_OPTIONS=nocheck debuild -us -uc
$ dpkg -x / -e ... path
$ dpkg -b path ...
2009-11-30 - unoverridable language default / ubuntu
Just now I logged on to a fresh Ubuntu server install for work. He who installed it had chosen a Dutch locale as default, which is fine, as long as my ssh environment can override it. It couldn't.
The ssh (on my client) and sshd (on the server) were okay:
SendEnv LANG LC_*
inssh_config
and,AcceptEnv LANG LC_*
insshd_config
.
The /etc/environment
file on the server was clean, so that couldn't break
anything either.
A quick search on the web yielded a bug from 2005 which is not fixed, it seems. Javier Serrano Polo was kind enough to provide a working fix:
Edit /etc/default/locale
and replace "LANG=nl_NL.UTF-8"
with
"LANG DEFAULT=nl_NL.UTF-8 OVERRIDE=${LANG}"
.
2009-11-04 - ssh and sshd trojaned
So one of my systems has had customized password-logging ssh and sshd applications running for quite a while. Yes, I've been r00ted :-(
How did I find out?
When using svn+ssh
protocol subversion repositories, I observed the
"Killed by signal 15" message as reported in debian
bug #366391, like this:
$ svn up At revision 44. Killed by signal 15.
The message is harmless and is caused by a specific combination of the versions of subversion and ssh. However, according to the bugreport this should've been fixed in openssh version 1:4.2p1-6 and I was running latest debian/lenny (openssh-client version 1:5.1p1-5).
That's odd. So I decided to strace
the app to find out more. There I noticed how one
of the processes opened /usr/lib/libv.o
and wrote to it.
That's even more odd. Why should I as a normal user have write powers in /usr/lib
?
When you think about it, /usr
should during normal operations even be read only for root.
Why is this a .o
(object file for static linking) file? And, worst of all, why hasn't
google heard of /usr/lib/libv.o
?
Looking at the data in /usr/lib/libv.o, it was not human readable, yet it used only a slight subset of the available character set. Perhaps a very trivial obfuscation method? I took the first 80 bytes and checked if I could add an integer and get something readable. No? Okay, deducted by an integer then? Yes, success.
$ od -t x1 /usr/lib/libv.o | head -n8 0000000 96 91 c5 df ca c7 d1 cd cd cd d1 ce ce d1 cd df 0000020 f6 c5 df 8d 90 90 8b df f6 c5 df 9b 9a 8b 9e 96 0000040 91 9a 9a 8c f5 96 91 c5 df ca c7 d1 cd cd cd d1 0000060 ce ce d1 cd df f6 c5 df 8d 90 90 8b df f6 c5 df 0000100 8f 9e 8d 9e 8c 9e 96 93 96 91 98 f5 96 91 c5 df 0000120 ca c7 d1 cd cd cd d1 ce ce d1 cd df f6 c5 df 8d 0000140 90 90 8b df f6 c5 df 8c 97 96 96 8b 9e 94 9a 8c 0000160 f5 96 91 c5 df ca c7 d1 cd cd cd d1 ce ce d1 cd $ dd if=/usr/lib/libv.o of=garbled.dat count=1 bs=80 $ for x in `seq 1 255` ; do echo -n "$x: "; perl -pe 's/(.)/chr((ord($1)-'$x')%256)/ge' garbled.dat | cat -A ; echo ; done <only garbage> $ for x in `seq 1 255` ; do echo -n "$x: "; perl -pe 's/(.)/chr(('$x'-ord($1))%256)/ge' garbled.dat | cat -A ; echo ; done <skipping 1 through 252> 253: gl8^^36,000,//,0^^^G8^^pmmr^^^G8^^bcr_glccq^Hgl8^^36,000,//,0^^^G8^^pmmr^^^G8^^n_p_q_gjgle^Hgl8^^ 254: hm9^_47-111-00-1^_^H9^_qnns^_^H9^_cds`hmddr^Ihm9^_47-111-00-1^_^H9^_qnns^_^H9^_o`q`r`hkhmf^Ihm9^_ 255: in: 58.222.11.2 ^I: root ^I: detainees$ in: 58.222.11.2 ^I: root ^I: parasailing$ in:
Drat.. that looks like passwords. And mine were in there too. And yes, both ssh and sshd seemed to be the culprits:
$ strings /usr/bin/ssh | grep '^out:' out: %s : %s : %s out: %s : %s : %s (%s) $ strings /usr/sbin/sshd | grep '^in:' in: %s : %s : %s in: %s : %s : %s (%s)
Had the "Killed by signal 15" issue not alerted me, I might not have found out that I was running a trojaned ssh. The behaviour of ssh being different from its supposed version, gave it away. This can also be observed in these following help and version messages:
$ /usr/bin/ssh -V OpenSSH_5.1p1, OpenSSL 0.9.8g 19 Oct 2007 $ /usr/bin/ssh.safe -V OpenSSH_5.1p1 Debian-5, OpenSSL 0.9.8g 19 Oct 2007 $ /usr/sbin/sshd -V sshd: illegal option -- V OpenSSH_5.1p1, OpenSSL 0.9.8g 19 Oct 2007 usage: sshd [-46Ddeiqt] [-b bits] [-f config_file] [-g login_grace_time] [-h host_key_file] [-k key_gen_time] [-o option] [-p port] [-u len] $ /usr/sbin/sshd.safe -V sshd: illegal option -- V OpenSSH_5.1p1 Debian-5, OpenSSL 0.9.8g 19 Oct 2007 usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file] [-g login_grace_time] [-h host_key_file] [-k key_gen_time] [-o option] [-p port] [-u len]
Other tell-tale signs — besides the world-writable libv.o and the messages being different — were extra ext2 attributes on the ssh binaries, statically linked files (the programs being larger but having less dependencies):
$ find /usr -type f -perm -o+w /usr/lib/libv.o $ lsattr /usr/bin/scp /usr/bin/sftp /usr/bin/ssh /usr/bin/ssh-keygen /usr/sbin/sshd s---ia------------- /usr/bin/scp s---ia------------- /usr/bin/sftp s---ia------------- /usr/bin/ssh s---ia------------- /usr/bin/ssh-keygen s---ia------------- /usr/sbin/sshd $ ls -l /usr/bin/sshd /usr/bin/sshd.safe -rwxrwxr-x 1 root root 1424243 2009-01-14 02:07 /usr/sbin/sshd -rwxr-xr-x 1 root root 474640 2009-01-14 02:07 /usr/sbin/sshd.safe $ ldd /usr/sbin/sshd | wc -l 11 $ ldd /usr/sbin/sshd.safe | wc -l 20
Further inspection of the ssh binary shows both "/usr/lib/libv.o" in the .rodata section, and embedded in the code (.text section):
$ objdump -D /usr/bin/ssh | grep movb ... 410fe2: c6 84 24 b0 01 00 00 movb $0x2f,0x1b0(%rsp) 410fea: c6 84 24 b1 01 00 00 movb $0x75,0x1b1(%rsp) 410ff7: c6 84 24 b2 01 00 00 movb $0x73,0x1b2(%rsp) 410fff: c6 84 24 b3 01 00 00 movb $0x72,0x1b3(%rsp) 411007: c6 84 24 b4 01 00 00 movb $0x2f,0x1b4(%rsp) 41100f: c6 84 24 b5 01 00 00 movb $0x6c,0x1b5(%rsp) 411017: c6 84 24 b6 01 00 00 movb $0x69,0x1b6(%rsp) 41101f: c6 84 24 b7 01 00 00 movb $0x62,0x1b7(%rsp) 411027: c6 84 24 b8 01 00 00 movb $0x2f,0x1b8(%rsp) 41102f: c6 84 24 b9 01 00 00 movb $0x6c,0x1b9(%rsp) 411037: c6 84 24 ba 01 00 00 movb $0x69,0x1ba(%rsp) 41103f: c6 84 24 bb 01 00 00 movb $0x62,0x1bb(%rsp) 411047: c6 84 24 bc 01 00 00 movb $0x76,0x1bc(%rsp) 41104f: c6 84 24 bd 01 00 00 movb $0x2e,0x1bd(%rsp) 411057: c6 84 24 be 01 00 00 movb $0x6f,0x1be(%rsp) ... $ objdump -D /usr/bin/ssh \ | sed -e '/[[:blank:]]movb/!d;s/.*movb[[:blank:]]*\$\(0x[0-9a-f]\{1,2\}\).*/\1/' \ | uniq | perl -pe 's/(.*)/chr(eval $1)/e' | tr -d '\n' | cat -A ; echo ^@^A^@^A^@^@man^@mkdir^@/usr/lib/libv.o^@man^@mkdir^@/usr/lib/libv.o^@man^@mkdir^@/usr/lib/libv.o^@Z ^@^E^@^A^@aeiouybcdfghklmnprstvzx^@-^@ A^@^A^B^@^A^@^A^@=^@=a^@/A^@\^@\^\s\r\f\v\n\t\b\a\0\-M?^@\^@9 ^_M-^C^@@^@M-d^H^@
Very unpleasant, all of this. But a good incentive to dive into examining binaries ;-)
2009-10-18 - rtpproxy with opensips / nat traversal
OpenSIPS combined with RtpProxy can be used to relay traffic between a SIP provider on the WAN and your SIP PBX on the LAN. The steps:
Download, compile and install rtpproxy. Then do the following to create an application level gateway user:
# useradd --system --home-dir /var/run/alg --create-home --skel /dev/null alg
Apply these patches to the sysinit files (debian) using patch -l
.
The DAEMON_OPTS in /etc/default/rtpproxy should have the external IP first, and the
internal IP second.
--- ~/src/rtpproxy-1.2.0/debian/rtpproxy-default.ex 2007-11-29 01:46:26.000000000 +0100 +++ /etc/default/rtpproxy 2009-10-18 20:56:39.000000000 +0200 @@ -7,4 +7,4 @@ # # Additional options that are passed to the Daemon. -DAEMON_OPTS="" +DAEMON_OPTS="-l 1.2.3.4/192.168.1.1 -s unix:/var/run/alg/rtpproxy.sock -d WARN"
--- ~/src/rtpproxy-1.2.0/debian/rtpproxy.init 2007-11-29 01:46:26.000000000 +0100 +++ /etc/init.d/rtpproxy 2009-10-18 14:34:19.000000000 +0200 @@ -11,9 +11,11 @@ # PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/bin/rtpproxy +DAEMON=/usr/local/bin/rtpproxy NAME=rtpproxy DESC=rtpproxy +USER=alg +PIDFILE=/var/run/alg/$NAME.pid test -x $DAEMON || exit 0 @@ -29,13 +31,13 @@ case "$1" in start) echo -n "Starting $DESC: " - start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ - --exec $DAEMON -- $DAEMON_OPTS + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --chuid $USER --exec $DAEMON -- $DAEMON_OPTS -p $PIDFILE echo "$NAME." ;; stop) echo -n "Stopping $DESC: " - start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ --exec $DAEMON echo "$NAME." ;; @@ -58,11 +60,11 @@ # just the same as "restart". # echo -n "Restarting $DESC: " - start-stop-daemon --stop --quiet --pidfile \ - /var/run/$NAME.pid --exec $DAEMON + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON sleep 1 - start-stop-daemon --start --quiet --pidfile \ - /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --chuid $USER --exec $DAEMON -- $DAEMON_OPTS -p $PIDFILE echo "$NAME." ;; *)
Next, download, compile and install opensips. Then apply these patches:
--- ~/src/opensips-1.6.0-notls/packaging/debian/opensips.default 2009-10-16 02:37:58.000000000 +0200 +++ /etc/default/opensips 2009-10-18 21:26:05.000000000 +0200 @@ -3,13 +3,13 @@ # # Set to yes to enable opensips, once configured properly. -RUN_OPENSIPS=no +RUN_OPENSIPS=yes # User to run as -USER=opensips +USER=alg # Group to run as -GROUP=opensips +GROUP=alg # Amount of memory to allocate for the running OpenSIPS server (in Mb) MEMORY=64
--- ~/src/opensips-1.6.0-notls/packaging/debian/opensips.init 2009-10-16 02:37:58.000000000 +0200 +++ /etc/init.d/opensips 2009-10-18 21:27:27.000000000 +0200 @@ -16,19 +16,20 @@ # Should-Stop: postgresql mysql radius PATH=/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/opensips +DAEMON=/usr/local/sbin/opensips NAME=opensips DESC=opensips -HOMEDIR=/var/run/opensips +HOMEDIR=/var/run/alg PIDFILE=$HOMEDIR/$NAME.pid DEFAULTS=/etc/default/opensips RUN_OPENSIPS=no +CONFIG=/usr/local/etc/opensips/opensips.cfg # Do not start opensips if fork=no is set in the config file # otherwise the boot process will just stop check_fork () { - if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" /etc/opensips/opensips.cfg; then + if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CONFIG; then echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/opensips debug instead" exit 1 fi
Last but not least, the opensips.cfg config file. This is far from perfect, I'm probably violating the SIP RFC, but it seems to work. Note that this only handles INVITE's and related messages. Note that you'll have to replace the example IP addresses sprinkled all over the config with real IP addresses.
####### Global Parameters ######### debug=0 log_stderror=no log_facility=LOG_LOCAL0 fork=yes children=4 disable_tcp=yes dns_try_ipv6=no auto_aliases=no ####### Modules Section ######## mpath="/usr/local/lib64/opensips/modules/" loadmodule "rr.so" loadmodule "sl.so" loadmodule "textops.so" loadmodule "tm.so" loadmodule "uri.so" loadmodule "nathelper.so" #loadmodule "uac.so" #loadmodule "xlog.so" modparam("nathelper", "rtpproxy_sock", "unix:/var/run/alg/rtpproxy.sock") ####### Routing Logic ######## route { #xlog("route in [$fu/$tu/$ru/$ci]\n"); # Sanity checks if (msg:len >= 2048) { sl_send_reply("513", "Message too big"); exit; } # Only support INVITE, ACK, BYE and CANCEL if (method != "INVITE" && method != "ACK" && method != "BYE" && method != "CANCEL") { sl_send_reply("503", "Service Unavailable"); exit; } # Add record routing headers if this is the first message in a dialog, # we need to stay in the middle. And, set the new $du by $si. if (!has_totag()) { record_route(); route("relay_by_source"); } # If this an in-dialog message, the message should have Route headers. if (has_totag()) { if (!loose_route()) { if (t_check_trans()) { t_relay(); exit; } exit; } } # Have rtpproxy handle SDP relaying if (has_body("application/sdp")) { if (method == "INVITE") { route("rtp_offer"); t_on_reply("rtp_answer"); } else if (method == "ACK") { rtpproxy_answer(); } } else if (method == "INVITE") { t_on_reply("rtp_offer"); } # Cancel RTP stream if (method == "BYE" || method == "CANCEL") { unforce_rtp_proxy(); } t_relay(); } route[relay_by_source] { if ($si == "192.168.1.30") { #uac_replace_from("", "sip:$fU@sip.voip-provider.tld"); #uac_replace_to("", "sip:$tU@sip.voip-provider.tld"); force_send_socket("1.2.3.4"); rewritehost("sip.voip-provider.tld"); } else { force_send_socket("192.168.1.1"); rewritehost("192.168.1.30"); } } route[rtp_offer] { if ($si == "192.168.1.30") rtpproxy_offer("ei"); else rtpproxy_offer("ie"); } onreply_route[rtp_offer] { if (has_body("application/sdp")) route("rtp_offer"); } onreply_route[rtp_answer] { if (has_body("application/sdp")) rtpproxy_answer(); }
Great. And first after posting this entry, I find the alg.cfg example file which is pretty similar to this one :-)
Update 2010-06-08
The above opensips.cfg does not work like expected. Instead, use the one below. Another thing worth mentioning is that you should use the latest opensips of the 1.6 branch (1.6.2), because the previous versions have had nasty bugs.
####### Global Parameters ######### debug=3 log_stderror=no log_facility=LOG_LOCAL0 fork=yes children=8 disable_tcp=yes dns_try_ipv6=no auto_aliases=no ####### Modules Section ######## mpath="/usr/lib/opensips/modules/" loadmodule "rr.so" loadmodule "sl.so" loadmodule "textops.so" loadmodule "tm.so" loadmodule "uri.so" loadmodule "nathelper.so" loadmodule "uac.so" loadmodule "xlog.so" modparam("nathelper", "rtpproxy_sock", "unix:/var/run/voipalg/rtpproxy.sock") ####### Routing Logic ######## route { #xlog("route in [$fu/$tu/$ru/$ci]\n"); # Sanity checks if (msg:len >= 2048) { sl_send_reply("513", "Message too big"); exit; } # Only support INVITE, ACK, BYE and CANCEL if (method != "INVITE" && method != "ACK" && method != "BYE" && method != "CANCEL") { sl_send_reply("503", "Service Unavailable"); exit; } # We can redirect inbound calls here if we want... if (method == "INVITE" && !($Ri =~ "^192\.168\.")) { if ($rU == "31123456789") { rewriteuri("sip:0612345678@sip.voip-provider.tld"); sl_send_reply("302", "Moved"); exit; } } # We do two things: # (1) rewrite SDP to use the RTP proxy # (2) forward all incoming messages to either 192.168.101.14 or sip.voip-provider.tld # Rewrite the SDP if (method == "INVITE") { if (has_body("application/sdp")) { # (unsure whether we need the FA options) if ($Ri =~ "^192\.168\.") { force_rtp_proxy("FAEI"); } else { force_rtp_proxy("FAIE"); } } } else if (method == "BYE" || method == "CANCEL") { unforce_rtp_proxy(); } # Always stay in the middle if (method == "INVITE") { record_route(); } # Find the correct destination if (!has_totag()) { route("relay_by_source"); } else if (!loose_route()) { sl_send_reply("503", "Expected routing headers"); } # Relay the message if (!t_relay()) { sl_reply_error(); } } route[relay_by_source] { if ($Ri =~ "^192\.168\.") { uac_replace_from("", "sip:$fU@sip.voip-provider.tld"); uac_replace_to("", "sip:$tU@sip.voip-provider.tld"); force_send_socket("1.2.3.4"); rewritehost("sip.voip-provider.tld"); } else { force_send_socket("192.168.101.30"); rewritehost("192.168.101.14"); } } onreply_route { if ($rm == "INVITE" && (status =~ "^18" || status =~ "^200")) { # (unsure about the FA options) force_rtp_proxy("FA"); } }
2009-09-08 - mysql ubuntu readline delete-char
No, editing your ~/.inputrc
does not work. And yes "\e[3~"
is the right
sequence. The way to get the DEL (forward delete) character to work in the mysql (mysql-client-5.1)
on Ubuntu/Jaunty is to edit ~/.editrc
and place the following lines in it:
bind "\e[3~" ed-delete-next-char bind "^R" em-inc-search-prev
chuckh1958 explains on the ubuntu forum
that the mysql client is not using readline
but editline
.
And as for using strace(1)
to find out what config files you might need:
mysql uses isatty
to check whether it should do any readline-ish stuff at all.
So you'll need to cheat around that, for example like this:
$ strace mysql -uuser -ppass somedb </dev/null 2>&1 | grep open.*/home $ cat >isatty.c int isatty(int i) { return 1; } ^D $ gcc -fPIC -shared -o isatty.so isatty.c $ LD_PRELOAD=./isatty.so strace mysql -uuser -ppass somedb </dev/null 2>&1 | grep open.*/home open("/home/walter/.editrc", O_RDONLY) = -1 ENOENT (No such file or directory) open("/home/walter/.mysql_history", O_RDONLY) = 4 open("/home/walter/.mysql_history.TMP", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
2009-08-17 - recoding avi to dvd using mencoder
The quick and easy way to burn your Midsomer Murders avi's to DVD. (Mind the "rm -rf DVD/" in there!)
$ cat >dvdauthor.xml <<EOF <dvdauthor dest="DVD"> <vmgm /> <titleset> <titles> <pgc> <vob file="dvd_movie.mpg" chapters="0,12:00,24:00,36:00,48:00,1:00:00,1:12:00,1:24:00,1:36:00,1:48:00"/> </pgc> </titles> </titleset> </dvdauthor> EOF $ mencoder -oac lavc -ovc lavc -of mpeg -mpegopts format=dvd:tsaf \ -srate 48000 -af lavcresample=48000 \ -vf scale=720:450,expand=720:576,harddup \ -lavcopts vcodec=mpeg2video:vrc_buf_size=1835:vrc_maxrate=9800:vbitrate=5000:dc=10:trell:mbd=2:keyint=15:vstrict=0:aspect=4/3:acodec=ac3:abitrate=192 \ -ofps 25 -o dvd_movie.mpg \ Midsomer\ Murders.s01e02.Written\ In\ Blood.avi ; \ rm -rf DVD/ ; \ dvdauthor -x dvdauthor.xml ; \ growisofs -dvd-compat -Z /dev/dvdrw1 -dvd-video -input-charset utf8 DVD/
2009-08-10 - prepending dates to program output
This convenient dateify
snippet is useful when a program (in my case
lightcount) doesn't prepend dates/times
to its logging output. Of course you could edit the program and add an strftime yourself,
but this is almost as cheap when the program does not produce much output and way cheaper to
implement.
#!/usr/bin/env perl # dateify(1) uses getc to avoid all perl input buffering # and prepends the current local time to every line read use POSIX 'strftime'; $| = 1; # disable output buffering (useful for tee(1)) while (1) { my ($s, $c) = ("", -1); $s .= $c while (($c = getc) ne "\n" && !eof); print strftime("%Y-%m-%d %H:%M:%S: ", localtime) . "$s\n"; last if eof; }
#!/usr/bin/env perl # dateify(1) uses getc to avoid all perl input buffering # and prepends the current local time to every line read # (fixed code on 2010-03-12) use POSIX 'strftime'; $| = 1; # disable output buffering (useful for tee(1)) while (1) { my ($s, $c) = ("", -1); $s .= $c while (($c = getc(STDIN)) ne "\n" and !eof(STDIN)); print strftime("%Y-%m-%d %H:%M:%S: ", localtime) . "$s\n" unless $s eq "" and $c eq ""; last if eof(STDIN); }
Example:
$ ( echo abc ; sleep 1 ; echo def ; sleep 1 ; echo ghi ) | dateify 2009-08-10 13:35:14: abc 2009-08-10 13:35:15: def 2009-08-10 13:35:16: ghi
2009-06-25 - wrong resolution / hp probook 4510s
My work got me a HP ProBook 4510s laptop recently. Ubuntu Jaunty amd64 installed fine and all drivers (all Intel and one Marvell NIC) work fine out of the box.
There's just one minor issue: often when booting, GNOME is loaded in a 800x600 display
mode. Which is way too small, obviously. Restarting gdm
fixes it, but that
becomes a pain after a while.
The problem can be seen in the following diff of Xorg.0.log
.
--- /var/log/Xorg.0.log 2009-06-25 09:43:10.643346190 +0200 +++ /var/log/Xorg.0.log 2009-06-25 09:44:52.279321015 +0200 @@ -181,10 +181,9 @@ (II) intel(0): Output VGA disconnected (II) intel(0): Output LVDS connected (II) intel(0): Output HDMI-1 disconnected -(II) intel(0): Output TV connected -(II) intel(0): Using fuzzy aspect match for initial modes -(II) intel(0): Output LVDS using initial mode 800x600 -(II) intel(0): Output TV using initial mode 800x600 +(II) intel(0): Output TV disconnected +(II) intel(0): Using exact sizes for initial modes +(II) intel(0): Output LVDS using initial mode 1366x768 (II) intel(0): detected 512 kB GTT. (II) intel(0): detected 65532 kB stolen memory. (==) intel(0): video overlay key set to 0x101fe
The fix is quite simple. Define the LVDS monitor (the LCD display) as used.
My xorg.conf
now looks like this:
Section "Device" Identifier "Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller (rev 07)" Driver "intel" Option "monitor-LVDS" "LCD-1366x768" EndSection Section "Monitor" Identifier "LCD-1366x768" Option "Position" "0 0" Modeline "1366x768" 69.30 1366 1382 1416 1466 768 770 776 788 -hsync -vsync EndSection Section "Screen" Identifier "Default Screen" Device "Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller (rev 07)" #Monitor "LCD-1366x768" EndSection
Update 2009-07-05
And, to get the built-in speakers to work (the headphone outlet already works by default),
you have to pass model=laptop
to the snd-hda-intel
module.
Add it as default option through the modprobe.d
directory.
# echo 'options snd-hda-intel model=laptop' >> /etc/modprobe.d/custom.conf
Update 2009-07-17
And, to get Skype to work, download the .deb package
(64 bit in my case) from skype.com, install it (dpkg -i), and do what the rest
of the internet tells you:
purge pulseaudio (it will remove the ubuntu-desktop metapackage, but
you don't need it) and install esound instead. Reboot.
The gdm startup sound still works and mplayer still plays audio, so it must be okay ;-)
P.S. To top it all off, the built-in webcam worked out of the box using the
already modprobe'd uvcvideo
driver.
2009-06-21 - recipe / chicken paksoi noodles
Prawn and paksoi stir-fry by Georgette Henson, adapted.
Ingredients:
- egg noodles, 250 (g)
- arachis oil (peanut oil), 3+ (T) (other oils should work fine too)
- sesame oil, 1+ (T)
- garlic cloves, 2, sliced
- optionally a sliced chilli pepper
- chicken breast, cut up in cubes, 200 (g)
- ginger, freshly grated, 1 (T)
- onions, 1+ (large), coarsely sliced (spring onions are even better)
- paksoi, 200+ (g), rinsed
- pine nuts, a handful, roasted
- optional masala/curry sauce, 1+ (T)
- optionally coriander, a couple of leaves
Put the noodles in a bowl, add enough boiling water (more than one liter) and leave to soak for 4 minutes. Drain and set aside.
Heat the oil in a wok — make it hot — add the garlic, the sesame oil and optionally the chilli pepper. Add the chicken and stir-fry (brown) for a minute or so.
Add ginger and the onions. Add the chopped white of the paksoi.
Roast the pine nuts in a separate clean dry frying pan at medium heat. Don't forget to toss them often.
Add the green of the paksoi, the optional masala/curry sauce, the roasted pine nuts and the noodles. Stir well.
When these last ingredients are all warm, you're done. Serve in a bowl with the optional coriander leaves on top.
2009-06-20 - slowloris / quick fix
If you're worried about slowloris tying up all your webserver's — most notably apache's — resources, the quick fix is to limit connections by IP address. This will of course limit functionality for all your clients using a proxy, but it's the easiest workaround workaround and works fine in the simplest of cases.
All you need is the the connlimit
(xt_connlimit) iptables(8)
module:
# iptables -I INPUT -p tcp --syn --dport 80 -m connlimit \ --connlimit-above 10 -j DROP # or REJECT
If you don't have this particular module, you can try to use the hashlimit
module
— if you have that — but it's not by far as effective, and if you're unlucky
it might only slow the attack down.
# iptables -I INPUT -p tcp --syn --dport 80 -j DROP # or REJECT # iptables -I INPUT -p tcp --syn --dport 80 -m hashlimit \ --hashlimit-name allow-syn-80 --hashlimit 1/sec --hashlimit-burst 10 \ --hashlimit-mode srcip -j ACCEPT
I don't want to give more attention to slowloris than necessary. I'm not convinced that full disclosure after only one — short-sighted, I admit — response from the apache team was the way to go. Perhaps limited disclosure on an apache mailing list would've been possible. But the loris is out of the bag now (very poor joke, I know, he he he), so it doesn't matter. What does matter is that there is a way more readable version of the tool out in python: pyloris. Use it to your advantage.
2009-06-19 - GNU as Hello World / jumps
The Hello World assembly snippet as found on the
2008 notes, extended to check the return value
of sys_write(2)
. This shows the usage of jmp
and that %eax
gets overwritten by the sys_write(2)
call with its return value.
--- hello.s 2009-06-19 09:27:10.667095772 +0200 +++ hello2.s 2009-06-19 10:21:38.062595546 +0200 @@ -8,8 +8,15 @@ movl len, %edx /* message length */ int $0x80 /* call kernel */ + xorl len, %eax /* check return value */ + jnz fail /* jump to fail if non-zero */ + xorl %ebx, %ebx /* set ebx to zero (EXIT_SUCCESS) */ + jmp done /* jump to exit part */ +fail: + movl $1, %ebx /* set ebx to non-zero (EXIT_FAILURE) */ +done: + movl $1, %eax /* system call number (sys_exit) */ - xorl %ebx, %ebx /* return value success */ int $0x80 /* call kernel */ .data
A more readable version using cmpl
instead of xorl
:
--- hello2.s 2009-06-19 10:21:38.062595546 +0200 +++ hello2a.s 2009-06-19 10:33:20.375095609 +0200 @@ -8,8 +8,8 @@ movl len, %edx /* message length */ int $0x80 /* call kernel */ - xorl len, %eax /* check return value */ - jnz fail /* jump to fail if non-zero */ + cmpl len, %eax /* compare return value */ + jne fail /* jump to fail if not equal */ xorl %ebx, %ebx /* set ebx to zero (EXIT_SUCCESS) */ jmp done /* jump to exit part */ fail:
Observe that jnz
and jne
are actually the same jump,
as can be seen from the following gdb(1)
output.
$ gdb ./hello2 [snip] (gdb) disass _start Dump of assembler code for function _start: 0x00000000004000b0 <_start+0>: mov $0x4,%eax 0x00000000004000b5 <_start+5>: mov $0x1,%ebx 0x00000000004000ba <_start+10>: mov $0x6000e4,%ecx 0x00000000004000bf <_start+15>: mov 0x6000f2,%edx 0x00000000004000c6 <_start+22>: int $0x80 0x00000000004000c8 <_start+24>: xor 0x6000f2,%eax 0x00000000004000cf <_start+31>: jne 0x4000d5 <fail> 0x00000000004000d1 <_start+33>: xor %ebx,%ebx 0x00000000004000d3 <_start+35>: jmp 0x4000da <done> End of assembler dump.
2009-05-27 - postfix / aliases / myhostname
If you specify myhostname
in your main.cf
postfix configuration,
make sure you add that hostname to mydestination
as well.
If you don't, your /etc/aliases
will be ignored, and you might end up sending
mail to root@myhostname when you want it all for yourself.
This can happen in the following common scenario:
- You have your workstation at your
mycompany.tld
intranet calledmydesktop
. Because it's an intranet, you can't receive mail from the outside. - You have postfix as your mailer daemon that uses
mail.mycompany.tld
as relay machine. - The relay machine validates sender addresses and doesn't like
myname@mydesktop
as FROM-address ("Sender address rejected: Domain not found (in reply to RCPT TO command)"). - To address the FROM-address problem, you set
myhostname
tomycompany.tld
. Mail tomyname@mycompany.tld
does get to your mailbox properly. At the same time this makes sure that recipients of your mail will be able to reply to your mail. Note that/etc/mailname
ormyorigin
sets theHELO
value whilemyhostname
sets theMAIL FROM
domain. - Now, this all works fine, unless you have set
mydestination
to something like:mydesktop, localhost.localdomain, localhost
. If you have, you're missingmycompany.tld
and mail to your own users will bypass local mail handling:/etc/aliases
won't be used like you expect it to. - The solution: add
mycompany.tld
to the mydestination.
To summarize:
# Updated 2009-06-05 myorigin = mycompany.tld canonical_maps = hash:/etc/aliases #myhostname = mycompany.tld
# Original alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mydestination = mycompany.tld, mydesktop, localhost.localdomain, localhost relayhost = [mail.mycompany.tld]
Two other unrelated postfix caveats:
- Postfix runs in a chroot jail by default (or at least on Debian/Linux it does).
If you change
/etc/resolv.conf
you must restart/reload it or your new DNS settings will not be used. - If you set
relayhost
, decide whether you want the MX or the A record of that host to be used. In the configuration mentioned above, that would be eithermycompany.tld
or[mail.mycompany.tld]
. Usually you will use the latter — the A record — so you shouldn't forget the brackets. When your DNS changes to not resolve MX records of subdomains to the MX of your toplevel domain, you'll be glad you didn't.
Update 2009-06-05
The above — that which is now line-through'ed —
was broken because you get mail delivered through the local delivery
when setting mydestination
. The fix is above in the config
snippet.
2009-05-24 - recipe / dads brown beans
Ingredients:
- brown beans, dried, 500 (g)
- molasses, 6+ table spoons
- salt, 3+ tea spoons
- vinegar, distilled, 6+ table spoons
Sort the beans (removing small rocks and bad beans) and soak the beans in room-temperature water for 8+ hours. Discard the soak water (this reduces flatulence).
Cook the beans in about 1.5 liters of water. You can start out with less, but you'll have to check periodically to make sure the beans do not dry out. This can take up to two hours as you want the beans to be overcooked, releasing starch, thickening the cooking liquid. Stir every now and then.
When the beans are almost completely dissolved, add the salt, the molasses and the vinegar. Depending on your taste and the types of ingredients, you might need more. You should now have a thick substance closer to mashed potatoes than to soup, with a sweet-sour taste.
Serve with crisp thick sliced bacon and potatoes.
2009-04-08 - thunderbird advanced config settings
A couple of useful Thunderbird about:config
settings:
;; Check all folders for new mail (default: false) mail.check_all_imap_folders_for_new = true ;; Sort all folders descending by default (default: 1) mailnews.default_sort_order = 2 ;; Some UTF-8 settings to pester non-UTF-8-users (defaults: false, ISO-8859-1) mailnews.reply_in_default_charset = true mailnews.send_default_charset = UTF-8
2009-04-05 - reading rfc documents on sony prs505
I recently bought the Sony PRS-505 reader — a digital book — and I am pretty content with it. The resolution and weight are fine. It handles darn slow, but it really is no problem having to wait one second for the next page... and it probably saves a lot of battery life.
The only two drawbacks I have found, is that it renders text (.txt) documents in a variable width font and it reboots on certain — not many — (broken?) pages in a couple of pdf files.
The first of these drawbacks is easily fixable by converting text documents to rich text files (.rtf) with a monospaced font. The embedded font/resolution then yields 71 (almost 72) characters per line in the small font mode. Fortunately, most RFC files are already limited to 72 characters and have enough double spaces that can be trimmed down to a single space.
Download this python script to convert text files to rich text files,
adjusted to fit the Sony PRS-505:
txt2prs505rtf.py
(view)
See this example for an already converted RFC:
rfc4930.rtf
2009-01-26 - unicodeencodeerror / python redirect pipe
Python has excellent Unicode support. Most of the time it just works.
However, when you want to redirect non-ASCII characters to a different program
through shell redirection, you will run into a UnicodeEncodeError
.
See the following example:
$ locale | grep LC_CTYPE LC_CTYPE="en_US.UTF-8" $ python -c 'print "\u20ac 3.50"' \u20ac 3.50 $ python -c 'print u"\u20ac 3.50"' € 3.50 $ python -c 'print u"\u20ac 3.50"' | cat Traceback (most recent call last): File "<string>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
Python calls something like isatty(3)
("is a TTY?") on the standard out file descriptor,
and when that returns 0 (false) it forces stdout
to use the ascii
codec.
This can be quite annoying if you want to use other shell tools (awk(1)
,
grep(1)
, sed(1)
, tr(1)
etc..) to quickly search through or
modify the output stream.
The solution is to replace the stdout
object with one that doesn't assume that
a non-terminal only likes ASCII. Add the following to your python code:
import codecs, locale, sys sys.stdout = codecs.getwriter(locale.getdefaultlocale()[1])(sys.stdout, 'replace')
It's not real pretty, but it works :-)
$ python -c 'import codecs, locale, sys > sys.stdout = codecs.getwriter(locale.getdefaultlocale()[1])(sys.stdout, "replace") > print u"\u20ac 3.50"' | cat € 3.50
2009-01-26 - gless / open binary and unknown files / gnome
Are you tired of gedit asking you what type of encoding a file is, when you just want to open the file to take a peek at the contents?
Use gless(1)
:
#!/bin/sh gnome-terminal -x less -f "$@"
You need the -f
or it will bypass the question of whether you want to open binary files
and assume no. (Resulting in a gnome-terminal(1)
that immediately closes.)
Update 2009-03-31
Mozilla likes to prepend some of these urls with a file://
.
Here's an updated version:
#!/bin/bash file="$1" ; shift if [ "${file:0:7}" == 'file://' ]; then file="${file:7}" fi gnome-terminal -x less -f -- "$file"
2009-01-05 - more or less useless tips and tricks
It's a new year, so it's time for some more more or less useless/useful tips and tricks, bundled together.
Like last time, they aren't worthy of a box div
on their own.
They only get a li
each.
- Fixing so you're printing A4 and not Letter in Ubuntu/GNOME
If you have your language settings set to en_US — like me — you're bound to have noticed that the default printing size is Letter. Letter is not A4, like you know, and A4 comes out of most printers here in Europe.
Solutions:# echo a4 > /etc/papersize # echo 'LC_PAPER=en_GB.UTF-8' >> /etc/environment # you do have en_US.UTF-8 set as LANG in there, right?
And, if those two do not provide the correct results, Firefox has aprint.postscript.paper_size
setting that likes an "a4" string as well. - Using Unix (GNU) utilities on Windows (download)
You might've spotted the UnxUtils.zip package on sourceforge.net, or you might not have because it is not always as easy to find the correct download location (it hasn't been updated since 2000-10-28). Also, the package contains some programs/files that most people do not need or that conflict with already existing windows binary names.
Therefore, for your pleasure and mine, I have repackaged the files. They are a bit old, but they work just fine. You getgrep
,tar
,less
,patch
,diff
,find
(renamed),wc
,wget
,netcat
and much more.
Get unxutilseasy.zip now and unzip it in yourWINDOWS
orSYSTEM32
directory so the files are in your path. - Did somebody send you a message consisting of only ones and zeroes?
Don't worry! Perl is your friend!echo 0100100001100101011011000110110001101111 | perl -pe 's/([01]{8})/chr unpack C,pack B8,$1/ge'
I leave encoding to binary as an exercise to the reader. - Need to access something (a website) on a remote lan when you only have ssh access?
Sometimes you are forced — for example by stupid web interfaces that insist on redirecting you to some LAN address — to connect to a LAN address that is not on your LAN.
Assume the following scenario:- I have shell (ssh) access to some machine (machine roger.example.com) that's connected to a LAN, with IPs 10.11.22.0/24.
- I want to reach some internal machine there, let's say 10.11.22.33 on port 80.
- You can use ssh forwarding for this:
ssh -L 9999:10.11.22.33:80 roger.example.com
— after logging in like always, you also get a tunnel from127.0.0.1:9999
to10.11.22.33:80
. - Sounds good. But wait, when logging on to the web interface on localhost, the site might decide to redirect
you to
10.11.22.33:80
. That address is not in your routing table, so you're screwed. iptables
comes to the rescue:iptables -t nat -I OUTPUT -d 10.11.22.33 -p tcp --dport 80 -j DNAT --to 127.0.0.1:9999
- Now you can connect to
http://10.11.22.33
and iptables will reroute it to localhost before it gets to the routing table. Pretty neat.
- Some ssh peculiarities worth remembering
/etc/environment
should not be treated as a shell script. Use only lines likeKEY=value
.- If you somehow find that you have trouble using
scp
orsftp
, make sure that your shell initialization scripts (.bashrc
and the likes, ran for non-login shells) do not print any information tostdout
or you get an error similar to this: Received message too long 1752131850 or no files written in case ofscp
.
Obviously you are allowed to print stuff after the mandatory[ -z "$PS1" ] && return
line that makes sure that non-shells exit before you do them any harm ;-)