Network Solutions Hijacks Domains

I dislike Network Solutions. I dislike them because their website is sub-par in terms of usability and because they charge ludicrous amounts of money to register domains. Not until but a few moments ago, however, did my ire for Network Solutions aspire to new heights.

Before, I just thought they were kinda crappy and overpriced. Now I place them in the category of down-right Despicable Internet Neighbors. Why this sudden angst? I’ll tell you why…

Network Solutions will hijack your domain and hold it hostage. Do not query for domain names using the Network Solution’s website! They will immediately register the domain for a period of four days, according to this blog post, and force you to purchase it only from Network Solutions. For a whopping $35.00 for one year.

Just watch:

rwoodrum@slard:~$ whois networksolutionsisshit.comWhois Server Version 2.0
Domain names in the .com and .net domains can now be registered
with many different competing registrars. Go to http://www.internic.net
for detailed information.
No match for "NETWORKSOLUTIONSISSHIT.COM".
>>> Last update of whois database: Thu, 21 Feb 2008 00:53:32 UTC <<<

Now I scamper off and use the Network Solutions Is Shit website to see if my domain is available. Within about a minute, what do I see? Take a gander:

   Domain Name: NETWORKSOLUTIONSISSHIT.COM
   Registrar: NETWORK SOLUTIONS, LLC.
   Whois Server: whois.networksolutions.com
   Referral URL: http://www.networksolutions.com
   Name Server: NS1.RESERVEDDOMAINNAME.COM
   Name Server: NS2.RESERVEDDOMAINNAME.COM
   Status: clientHold
   Updated Date: 20-feb-2008
   Creation Date: 20-feb-2008
   Expiration Date: 20-feb-2009>>> Last update of whois database: Thu, 21 Feb 2008 00:57:38 UTC <<<

Wow. Network Solutions is seriously shit. Now I go to GoDaddy, a real registrar, and the domain is not available. Nope, it has been sealed down with a $35.00 price tag.

Dear Network Solutions,

I will make sure no one I know is ever your customer. You have wronged the Internet and now you shall pay.

Update: After reading this comment on the domaintools.com blog, I decided to give Network Solutions a call. Here’s the transcript:

—14 minutes 39 seconds on hold—

14 minutes 39 seconds later…

I spoke with Amanda. The conversation went like this:

Amanda: Thank you for calling network solutions. Can I have your domain name please?

rwoodrum: Well I’m trying to register a domain but you guys placed a hold on it when I looked it up on your site.

Amanda: Let me take that off of there for you.

rwoodrum: [amazed she knew exactly what I was talking about and was doing exactly what I wanted]

Amanda: I assume you don’t want to register the domain with us?

rwoodrum: uhhh, no

Amanda: That should come off in the next few minutes but it could take up to 24 hours.

—2 minutes later—

Domain freed.

I told my story there as well.

Obama’s Legislative Accomplishments

This page intentionally left blank.

<crickets>

Using the Ruby LDAP extension library

So I was recently working on a ruby/rails project which had to interact with OpenLDAP. This was easy enough using this Ruby/LDAP extension library found on Sourceforge (LNUX). As a quick aside, there is also the whole ActiveLDAP RubyForge project which treats LDAP as another backend just like a SQL database with different adapters, etc etc. For now, however, I will discuss the extension library and will perhaps go into ActiveLDAP some other time.First and foremost, a good reference and place to start is the rdoc documentation for the extension library. With this in hand, it is easy to get started interacting with an LDAP server. In my examples, I’m assuming use of OpenLDAP. I’m also running on a Debian/sid system with the following package installed: libldap-ruby1.8. I have a fresh DIT with a base of dc=foo,dc=com and TLS configured like so in slapd.conf:
TLSCACertificateFile /etc/ldap/ssl/ca.crt
TLSCertificateFile /etc/ldap/ssl/localhost.foo.com.crt
TLSCertificateKeyFile /etc/ldap/ssl/localhost.foo.com.key
TLSVerifyClient never

Note: A very common gotcha with openldap/TLS configuration is that the certificate does not match exactly with the hostname. The cn of the server certificate MUST be the fqdn of the host and that fqdn MUST be used for the connection. This can also be the case for the client, but TLSVerifyClient is set to “never” by default as seen above. What does this mean? This means that if your OpenLDAP server is on baz.foo.com, the cn of the certificate must be “baz.foo.com” and you must use “baz.foo.com” to connect as the client. Anything else and you’ll probably see an error like “Error in the certificate.” Note that your ca certificate must also match accordingly.

My LDAP begins with the following:
rwoodrum@frums:~/tmp$ ldapsearch -x -W -D cn=admin,dc=foo,dc=com -b dc=foo,dc=com
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <dc=foo,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#</dc=foo,dc=com>
#
# foo.com
dn: dc=foo,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: foo
dc: foo
#
# group, foo.com
dn: ou=group,dc=foo,dc=com
ou: group
objectClass: top
objectClass: organizationalUnit
#
# bar_group, group, foo.com
dn: cn=bar_group,ou=group,dc=foo,dc=com
cn: bar_group
description: the bar group
gidNumber: 3000
objectClass: posixGroup
objectClass: top
memberUid: rwoodrum

And now, we’ll use a trivial module to modify this group, changing the memberUid attribute. Here’s the module code that will pull in from elsewhere:

require 'ldap'module FooLDAP
  def self.setup_ldap_connection
    conn = LDAP::Conn.new(host='localhost.foo.com')
    conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
    begin
      conn.start_tls.nil?
    rescue
      conn.perror("debug")
      raise "error during start_tls"
    end

    conn.simple_bind(dn = 'cn=admin,dc=foo,dc=com', password = 'secret')

    begin
      !conn.bound?
    rescue
      conn.perror("debug")
      raise "error during simple_bind"
    end

    return conn
  end  def self.update_bar_group
    conn = setup_ldap_connection
    conn.modify('cn=bar_group,ou=group,dc=foo,dc=com', {"memberUid" => ["ryan_woodrum"]})
    conn.unbind
    return
  end
end

And now from outside, use the module:

require 'foo_ldap'

FooLDAP.update_bar_group()

After running, you can see the the memberUid attribute has changed inside of ldap:
rwoodrum@frums:~/tmp$ ldapsearch -x -W -D cn=admin,dc=foo,dc=com -b dc=foo,dc=com cn=bar_group
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <dc=foo,dc=com> with scope subtree
# filter: cn=bar_group
# requesting: ALL
#
#
# bar_group, group, foo.com
dn: cn=bar_group,ou=group,dc=foo,dc=com
cn: bar_group
description: the bar group
gidNumber: 3000
objectClass: posixGroup
objectClass: top
memberUid: ryan_woodrum
... snip ...
</dc=foo,dc=com>

Quid est demonstratum.

Systems Engineer vs. Systems Administrator

This is something of a hotbutton issue with me at the moment and deserves a blog post.

Call me a systems engineer, call me a systems architect. Don’t call me a system administrator or an “ops guy.” Why? Because they’re totally different. Some might disagree with my position in this similar, somewhat dated discussion on System Engineering vs. System Administration. I patently disagree, however, that they are equal and I patently disagree that the former is “resume inflation.”

I’ve discovered that there are a lot of Software Engineers, SDE’s whatever the hell you want to call them that are seriously arrogant bastards. Ok, maybe they’re not arrogant bastards. Maybe their exposure has simply been to “dumb ops guys” that are perhaps trained to press buttons when something breaks. Maybe they’ve just sat on a throne for such a long time that they can do no wrong. Maybe they have some notion in their head that they can do what everyone else can but no one can do what they can.

What might that “ops guy” do or the guy in your “IT” department do? He might fix your piece of shit Outlook. He might fix your piece of shit @microsoft_product. He might revel in buying a new computer all the while oggling over new flim-flams on the motherboard or some crap like that. He might be super uber and haxxorz and do something in BIOS!!111

Now, don’t get me wrong, there’s nothing wrong with doing that stuff. And, yes, years and years ago I did in fact do the same thing. You’d probably be hard-pressed to find anyone with a degree in computer science that hadn’t done that sort of thing. Now? Now I don’t give a crap about that stuff. I don’t give a crap about configuring apache for the 80 gazillionth time. I don’t care about setting up authentication with openldap for the 80 gizillionth time. What I do care about is figuring out real engineering problems. Why? Because that’s what’s challenging. How do I make large scale systems interact? How do I architect something such that it’s scalable? How do I automate those mundane tasks? What software can I write to make it easier?

These are not the same sorts of things as reading your logs for the, yes, 80 gazillionth time to figure out why postfix didn’t send some random mail. Not the same thing as writing your 10 line bash script to find files meeting criteria foo, bar, baz, and bit. Again, is there absolutely anything wrong with those sorts of tasks? No way. Do I ever find myself doing them? Sure. Is it my primary talent? Nope, because my time is spent better elsewhere.

As pointed out in this blog post, some places disallow use of the term “engineer” because it’s tied up in certifying bodies, etc etc. I’m not talking about that sort of thing. And I’m not talking about “resume inflation” equating the garbage guy with a “waste management engineer” or some crap.

Am I the only one that makes this distinction??

John McCain’s bump on his cheek, what is it?

Some of you may have noticed that John McCain has a bump on his cheek.  There are, of course, somewhat expected rumors afloat about skin cancer, etc etc.  In fact, they are nuts.  He stores nuts there for winter.

mccain storing nuts

2008 Widespread voter disenfranchisement

It’s unfortunate that the Democratic National Committee and the Republican National Committee have disenfranchised so many voters this year.

Are you from Florida?  Are you from Michigan?  Do you live in Washington and think your primary vote means anything?

Guess again.  Your vote doesn’t count for squat.

At the time of this writing, Florida and Michigan are two very large states whose voters have had their voices sileneced because they moved their primary dates to before February 5th.  That’s a shame.  I guess those tens of millions of people don’t matter.  For shame on the Democratic and Republican parties for having such arrogance.  I encourage people to use the power of the purse to show them that your votes do count.  Do not give a cent to these organizations until you are no longer disenfranchised.  Of course, the Republicans are always very good at presenting a unified front, so if anyone who is considering giving money to the RNC actually reads this, I doubt they’ll listen.

What about Washington?  Sanctioned by the party, the state has a draconian caucus system which determines allocation of ALL delegates.  I wonder how many Washington state residents don’t realize that their mail-in primary ballot, like my own, means absolutely nothing.  Personally, I don’t like to hear that my vote is a vote in a beauty contest.   As a matter of fact, it flat out pisses me off.

Postfix: Sending “do not reply” mail to /dev/null

If you want to set up a do-not-reply address in Postfix for the local delivery transport, it’s easy enough to do so via aliases:
do-not-reply: /dev/null

This will throw all the locally delivered mail to the do-not-reply alias into the file /dev/null.

What about if you have a more complex setup with stuff like relay_domains, transport_maps, relay_recipient_maps, etc.? Here’s how you do it.

In my setup, I have a relay_domain specified for a domain; let’s say foo.com:
relay_domains = $mydestination, foo.com

Furthermore, I have a relay_recipient_map defined to weed out certain mail such as to only relay to users that exactly exist where I’m about to relay for foo.com:
relay_recipient_maps = hash:/etc/postfix/relay_recipients

The contents of /etc/postfix/relay_recipients might look like:
bob@foo.com na
bill@foo.com na

I also have a transport_maps specified:
transport_maps = /etc/postfix/transport

This is where the bulk of the magic happens. The contents of /etc/postfix/transport might look like:
do-not-reply@foo.com local:
foo.com :[mail-exchanger.bar.com]

In this transport map, I’m specifying that I want postfix to use the local transport agent for ‘do-not-reply@foo.com’. For everything else, I want it to send it to a relay, in this case I want to relay all foo.com mail (for which I am the MX record) to a different provider/service where the actual mail boxes live. So I relay foo.com mail to mail-exchanger.bar.com. (See the manpage on transport for more information and also check out the main.cf documentation [and everything else on postfix.org].)

So… you end up with all this in the end:

  • ‘do-not-reply@foo.com na’ in your relay_recipient_map
  • ‘do-not-reply@foo.com local:’ in your transport
  • ‘do-not-reply: /dev/null’ in your aliases file

Mail to do-not-reply@foo.com (for which a mailbox doesn’t really exist at the bar.com service):

  • is checked against relay recipients
  • moves on to transport where it is decided that it should be delivered locally
  • delivered to the do-not-reply local user
  • is sent to the bit bucket

Voila. Yay postfix configuration!

Form not submitting on enter key with multiple form fields

So this is one of those really stupid things that was virtually impossible to find on google. One permutation was the golden child and brought me to this wonderful blog post.

So I’ve got a stupid bug I’m trying to fix. Seems innocuous enough. Nope, one of those stupid, finicky, browser things. I have an AJAX form with multiple fields that has no submit button; instead onsubmit deals with what to do with the form. So my form looks simply like so:
<% form_field('password', @thing) do %>
<%= password_field(:thing, :password) %>
<%= password_field(:thing, :password_confirmation) %>
<% end %>

One may expect that if you entered information in these fields and pressed the enter key, it’d submit. It doesn’t. At least not in Firefox… which means IE has no hope. Safari, however is “smarter” and it actually works. But I digress…

If you had this form with a single field, it’d work like a charm:
<% form_field('password', @thing) do %>
<%= password_field(:thing, :password) %>
<% end %>

So the answer is simply that you can’t submit a form by pressing enter when having more than 1 input field. At least not with a submit button.

The solution?

Add an invisible input button:
<input style="display: none" type="submit" />

Stupid. Dirty. Hack.

***Update: This, of course, doesn’t work on shitty IE browsers. They do not like the style=”display: none” and probably do something “clever” like optimize it into non-existence. They will, however, accept it if you use a style=”width:0px;height:0px;border:none”.

Even more stupid and dirty and hackish. But it’s a Microsoft product, what do you expect?