| rejecting residential zombies with qpsmtpd |
[Aug. 14th, 2007|03:29 pm] |
Qpsmtpd continues to be fun. For the past week or so, danga.com's mail has been running with qpsmtpd in front, instead of Postfix, and qpsmtpd now handles:
-- normal logging to syslog -- logging all connections in structured/indexed way to mysql, many columns per connection -- SMTP AUTH, letting me/friends use danga.com as our outgoing mail server -- check_earlytalker (reject clients who speak before spoken to, as lot of spammers do) -- counting bad commands (reject clients who HTTP POST to port 25 via open web proxy) -- DNS RBL checks -- rejecting non-members from posting to GNU Mailman lists -- not letting people send mail as @danga.com, @bradfitz.com, etc, etc without SMTP-AUTH -- rejecting mails to non-existent users (no bounces later, 5xx immediately) -- spam checks via spamassassin -- virus (and phishing) checks via ClamAV's clamd -- queuing to postfix (which then delivers to local users via .forward/.procmailrc/Maildir, whatever)
My Postfix config, meanwhile, has shrunk to barely anything.
But after analyzing my logs in MySQL, I still wasn't happy. I saw that almost all my spam (~98%) came from residential DHCP/DSL/Cable connections, with stupid-looking, easily-recognizable hostnames, like:
+---------------------------------------------------+
| remotehost |
+---------------------------------------------------+
| pool-71-187-1-147.nwrknj.fios.verizon.net |
| APointe-a-Pitre-103-1-66-27.w80-8.abo.wanadoo.fr |
| 80-219-140-217.dclient.hispeed.ch |
| dsl-189-133-79-229.prod-infinitum.com.mx |
| c-71-196-65-212.hsd1.fl.comcast.net |
| dsl-189-174-204-42.prod-infinitum.com.mx |
| 150.218.111.218.klj03-home.tm.net.my |
| 201-25-211-207.fnsce702.dsl.brasiltelecom.net.br |
| d83-186-127-150.cust.tele2.be |
| 24-159-245-214.dhcp.mdsn.wi.charter.com |
| aolclient-68-202-241-155.aol.cfl.res.rr.com |
| c-71-61-26-51.hsd1.pa.comcast.net |
| i05v-87-90-179-109.d4.club-internet.fr |
| 85.137.89.143.dyn.user.ono.com |
| c-76-100-225-155.hsd1.md.comcast.net |
| dslb-088-074-000-186.pools.arcor-ip.net |
| pD955ED51.dip.t-dialin.net |
| 183.42.33.65.cfl.res.rr.com |
| 82-42-29-1.cable.ubr02.knor.blueyonder.co.uk |
| client-200.121.44.138.speedy.net.pe |
| c-68-58-108-131.hsd1.in.comcast.net |
| host81-154-148-241.range81-154.btcentralplus.com |
| 216-199-78-234.atl.fdn.com |
| 218.206.98-84.rev.gaoland.net |
| cpe-65-28-157-135.bak.res.rr.com |
| 82-45-185-97.cable.ubr01.chel.blueyonder.co.uk |
| KH222-156-64-178.adsl.dynamic.apol.com.tw |
| dslb-084-056-113-198.pools.arcor-ip.net |
| 195.64.189.72.cfl.res.rr.com |
| dsl-189-179-129-154.prod-infinitum.com.mx |
| cpe-24-175-188-97.stx.res.rr.com |
| 78-56-100-93.ip.zebra.lt |
| 75-131-161-195.dhcp.spbg.sc.charter.com |
| host-81-190-121-194.gdynia.mm.pl |
| c9112907.rjo.virtua.com.br |
| ppp-124.120.110.148.revip2.asianet.co.th |
| dsl-189-144-11-85.prod-infinitum.com.mx |
| 201-95-47-232.dsl.telesp.net.br |
| 202.31.101-84.rev.gaoland.net |
| i05v-212-194-122-1.d4.club-internet.fr |
| 201-88-68-211.cbace700.dsl.brasiltelecom.net.br |
| dslb-082-083-049-211.pools.arcor-ip.net |
| 89.140.22.68.static.user.ono.com |
| cpe-76-170-82-98.socal.res.rr.com |
| 112.75.128.219.broad.fs.gd.dynamic.163data.com.cn |
| S01060015e97b2781.du.shawcable.net |
| c-24-8-151-233.hsd1.co.comcast.net |
| 20150032076.user.veloxzone.com.br |
| host-69-221-111-24.midco.net |
| 67-130-61-6.dia.static.qwest.net |
+---------------------------------------------------+
So I wrote a little Perl module (to be released) that incorporates a few dozen tests and regexps, looking for the IP address (or part of it) encoded in the hostname any number of totally f'ed up ways, and also double-checking that the user isn't some home Linux user running their own mail server... if their HELO hostname resolves to their source IP, I allow an ugly reverse DNS hostname. You often can't control your reverse. And forward DNS is free, so it's not an unreasonable barrier to entry.
Check out this table: http://bradfitz.com/hacks/antispam/lj-example-table.txt
In conclusion, a lot can be learned from the (IP, reverse DNS of that IP, declared HELO host) tuple. I'm now rejecting 50% of incoming connections at the MAIL FROM stage (have to give them a chance to AUTH after HELO), based on the (IP, reverse DNS, HELO host) alone. I reject the remaining 50% (25% of total) via spamassassin, check_earlytalker, and dsnbl, and then I queue/deliver 25% of the total email to users on danga.com.
Yay qpsmtpd! |
|
|
| AC switching, monitoring... |
[Apr. 13th, 2007|02:28 pm] |
My sewer's sump system has 3 pumps...
- 2 in big tank. These have float sensors and only turn on when the fluid level is high enough. Only one needs to be on at a time. Ideally, I should have a switch box install that makes sure only one gets power at a time, switching it back & forth every so often. Otherwise if one is installed just a millimeter above the other, one will always get all the work and the second will never go, and so they won't wear equally.
- 1 in little (rainwater?) tank. Also has a float sensor.
My deck is currently still torn apart because I'm still paranoid that once I close it, something will break again and I won't notice.
I'd like to be able to remotely monitor (and/or get alerts) about the pump health.
Here's what I propose (and what I need help on)....
Small Linux box (Mini-ITX or Gumstix) in a water-proof box, with WiFi, with serial ports (or Serial over USB), controlling X10 Universal Adapters (if they're strong enough for the amperage?), or controlling some relays.
So yes, I could do the switching between the two tanks from the computer with just a remote relay control, including varying the offsets, such that one pump doesn't always get the same hours of the day, but what I actually want to do is measure the power draw per-pump.
Basically I want to make sure the pumps' floats and motors are still working, by measuring the power draw on each of the three plugs.
Any ideas how I can measure this?
I'm also willing to pay somebody to build me some Serial/Parallel/USB device to do this, if any CSE-types are out in the audience. I'd rather spend a couple hundred on a solution that makes me happy, than spend a few hundred on a switching box and seal up the deck and never know if it's going to blow up again (or already has!).
Thanks! |
|
|
| Vocab Quizzer |
[Mar. 17th, 2007|04:48 pm] |
Updated my 7+ year old vocab quizzer program to be web-based. Actually I just rewrote it all.
Screenshot:

It keeps track of your history of failures, stats per-word, intelligently picks what word to give you next, and keeps bugging you about words until you've shown a history of getting it right (both times in a row most recently, and overall percentage).
You can create/change word lists, play again, etc.
I'm sure I'll add more later as I work on it more. But for now, I have a bunch of words to learn for a test on Tuesday. Clothing, colors, bunch of adjectives...
Time to stop hacking and start studying. |
|
|
| Garage Door Opener -- done |
[Mar. 17th, 2007|11:29 am] |
Update on garage door opener via Treo: done.
Final solution: no SSL, inline JavaScript that changes the URL to ...?t=[unixtime]. If that time is recent, garage door opens.
All checked into svn (so I don't have to remember this all later), and tested... works great.
(As opposed to email, SMS, etc... I just have to hold one key and it works. Even if it takes 5-10 seconds, it's quicker than running inside, taking off shoes, etc...) |
|
|
| Treo garage door opener |
[Mar. 17th, 2007|12:47 am] |
I wired up:
Treo hot key to URL... Linksys port forward 443... Perlbal (speaking SSL), forwarding to... xinetd listening on random port... script speaking HTTP, which... uses "heyu" to send X10 command over serial port, to.... momentarily close a relay, which... closes the circuit on a new set of garage door wires I ran, which... opens (or closes) my garage door.
So basically bike home (either bike), pull out phone, hold down the "G" key for 2-3 seconds, browser loads page, and my garage door opens.
Except the treo browser crashes and the phone reboots after I agree that it's a self-signed cert. And the server never gets the HTTP request. If I do it from my real browser, the garage door opens as expected.
So do I....?
- Fix SSL issues in Perlbal that caused it to crash? But all browsers work on Perlbal, and presumably the Treo "works on all SSL servers". Or something.
- Run this not over SSL? I'm afraid of T-Mobile pre-fetching my shit "for me" and opening my garage door while I'm at work. Much less chance of that/related crap with SSL. I don't even know if the SSL termination is on my phone or elsewhere.
- Use stunnel or something? (no fucking way I'm getting near Apache and SSL... I hate that stuff.)
But maybe it's in the end the self-signed certs that crash the Treo, not the server. *shrug* But hell if I'm paying for a cert. |
|
|
| emacsclient love |
[Jan. 25th, 2007|11:27 am] |
indexing all code on dev machine (package/function -> file/line) + webapp + emacsclient == love
also, smart bookmarks. now, from webbrowser (typically open!), ctrl-L, "c SEARCHTERM", select... click/enter, and emacs is showing it, positioned at right line.
<3 |
|
|
| Fun with Unix |
[Dec. 21st, 2006|09:00 am] |
What do you do if you have a tarball (Windows users: "zip file") that's taking up most a lot of the filesystem ("disk space"), not leaving you enough room to uncompress it?
Easy:
-- cut the archive file into bite-sized chunks (with, say, dd(1)), starting at the back of the file, and calling truncate on the original file as you go backwards. Or maybe you have enough space, so you don't need to truncate. Easier. Then just delete the full-sized archive at the end of your chunking.
-- pipe all the chunks (in foward order!) into tar -zxvf - ("uncompress"), unlinking each chunk as you move on to the next.
Sure, this doens't let you resume later if there's a failure, since you killed your original chunks. But I'm assuming you can get the archive back if you need it. |
|
|
| Friday Hijinks |
[Apr. 14th, 2006|02:20 pm] |
Payphone in the office now posts to the sixaphone podcast blog:
 (C) ljkrissy 2006; photo used without permission
 (C) revmischa 2006; photo used without permission
Aaah yea'. |
|
|
| fakesms server |
[Apr. 5th, 2006|06:37 pm] |
The cool thing about having an extensible Jabber server/baseclass is that I can crank out crazy Jabber servers in minutes.
For testing LJ's upcoming SMS integration, we needed a way for developers to pretend they were sending and getting SMSes from their developer LJ installs. Also, non-technical employees needed to test, so command-line clients are out. Web stuff is too painful async. Working with carriers/SMS aggregators is 10x more painful than all that combined.
Solution? Jabber server, of course.
I forgot about this until I got a Google News Alert about it: http://cvs.livejournal.org/browse.cgi/livejournal/bin/fakesms-djabberd
Users log in with username of 5551212 (or whatever phonenumber) and a password of "smstest" (arbitrary), then it's like they have that cellphone, from LJ's point of view.
Here's the server: http://cvs.livejournal.org/browse.cgi/livejournal/bin/fakesms-djabberd?rev=1.3
The only new code are the two FakeSMS modules: http://cvs.livejournal.org/browse.cgi/livejournal/cgi-bin/DJabberd/Delivery/FakeSMS.pm?rev=1.1 http://cvs.livejournal.org/browse.cgi/livejournal/cgi-bin/DJabberd/RosterStorage/FakeSMS.pm?rev=1.1
First one delivers messages into LJ (misc/fakesms.bml endpoints, only enabled for developers), and the other one just puts the sms@$SERVER item into users' rosters, to ease testing.
(SMS from LJ to Jabber is handled by the LJ code when $IS_DEV_SERVER) |
|
|
| Six-a-phone |
[Apr. 5th, 2006|03:35 pm] |
With our new public Asterisk server, Jonathan Steinert ( hachi) set up a phone in the office which goes straight to the voice post gateway, without dialing.
I then rigged that up to automatically post to sixaphone when you hit just "#" (from the office context) as your number, bypassing all the auth. Also bypassing all the annoying options, so it's always public. And Frank the Goat always appreciates our calls, not just a quarter of the time like all you people.
So yeah, best podcast ever: http://sixaphone.livejournal.com/
For people in the office: -- pick up the phone next to Jonathan/Sippey -- wait for "Enter your authorized phone number...." and any time after the word "Enter", press #. -- record. -- press #. |
|
|
| LiveJournal Radio! |
[Jan. 12th, 2006|08:20 pm] |
Listen to public LiveJournal voice posts, non-stop:
http://radio.bradfitz.com/ljcalls.m3u
Enjoy, while it lasts. I may take it down if it takes up too much bandwidth.
This is not an official LiveJournal feature (yet?). This is all done on my own server, using public data, as anybody else could do. |
|
|
| How to make web screenshots |
[May. 13th, 2004|11:43 am] |
$ vncserver -geometry 800x800 -depth 24 $ DISPLAY=:1 mozilla-firefox -P "Screenshot" & $ DISPLAY=:1 mozilla-firefox -P "Screenshot" -remote "openurl(javascript:window.open('http://www.livejournal.com/','','fullscreen=yes,toolbar=no,width=800,height=800'))" $ DISPLAY=:1 import -window root -resize 200x200 lj-shot.jpg $ eog lj-shot.jpg

score |
|
|