all mail servers must have a PTR record with a valid Reverse DNS entry

After we moved from our own server to Linode I started getting these bounce messages from Comcast. Reverse DNS just means that if you have an IP address you can find the domain associated with it. In my case I have lots of domains at the same IP address but use one for sending mail. I didn’t know what a PTR record is so I looked it up. Wikipedia says that “IPv4 uses the in-addr.arpa domain and the ip6.arpa domain is delegated for IPv6. The process of reverse resolving an IP address uses the pointer DNS record type (PTR record).”

On our old server we did our own DNS hosting and all of the info was contained in a file. So I knew about MX records, A records, etc. Linode uses a control panel to do the DNS setup so the setup is a bit different, but the same info is there. I had an A record for the domain that was sending the email, mail.machinename.com, and one for the domain that the email was coming from i.e. support@mycompany.com.

I checked with intoDNS to make sure that everything was set up correctly and I did in fact have a PTR record that pointed to the right place. “Your reverse (PTR) record: 192.168.255.173.in-addr.arpa -> mycompany.com”.

The clue came in a bounce from a different domain. The message said that the reverse DNS for 2500:34e80::f03c:92ee:fg70:ab93 was not found. It turns out that this is an IPv6 address. It appears that Linode is using an IPv6 address for the port I send mail from. To get a reverse DNS set up for that address I needed to set up an AAAA record in the Linode control panel, wait a while for it to propagate to Linode’s DNS servers, then set up reverse DNS for the IPv6 address.

I waited a day for the change to propagate and now my Comcast emails are going through fine.

UIImage Crash on iPod Touch

While testing my app on an iPod Touch I started getting an out of memory crash. It turns out that when using imageNamed: iOS keeps the picture around in case it is needed later. It is supposed to remove it from memory when it needs more memory, but it is slow to do so and causes the app to crash. I replaced it with imageWithContentsOfFile: and the crashes went away.

VM Tracker.png


/ Put the picture on the screen. Most will be jpegs
    //NSString *pictFileName = [NSString stringWithFormat:@"%@.jpg",pictName];
    NSString *pictFile = [[NSBundle mainBundle] pathForResource:pictName ofType:@"jpg"];
    if (  [PICT_TYPE isEqualToString:@"png"] ) {
        //pictFileName = [NSString stringWithFormat:@"%@.png",pictName];
        pictFile = [[NSBundle mainBundle] pathForResource:pictName ofType:@"png"];
    }
    
    //self.imageToDisplay  = [UIImage imageNamed:pictFileName];
    self.imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];
    

From the documentation for imageNamed:,

This method looks in the system caches for an image object with the specified name and returns that object if it exists…
If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.

So for all of my icons that remain on the screen, e.g. microphone, speaker, checkboxes, I use imageNamed:. They are small and reused so they belong in the cache. For the main image on the screen, which is large, there will most likely be lots of other images used before it is used again. The cache will be purged before the app gets around to using it again so there is no point to putting it there in the first place.

Non-Hackers as Founders

This is a continuation of my thoughts about founders that I started in the post on Women as Founders. There are literally thousands of startups out there, most of which you’ve never heard of—either because the solve a problem that you don’t have or because they never got the number of users required to be a sustainable business. I started at the beginning (2005) and looked through the list of startups funded by Y-Combinator. Looking through the list from the first few years, most of the startups solved problems that other hackers had. Part of this is no doubt due to the fact the Y-Combinator was founded by successful hackers. But part of it was not doubt due to the fact that the founders were solving a problem that they had. Most of the startups seem to be other solving technical problems, website design, secure payments, photo editing. Or they solve a communication problem, or social connection problem.

I’ve started several web-based companies. The ones that failed to get up and running did so because I was relying on other people to do the actual development. In 2001 my cousin was getting married and I thought it would be good to put up a website where people could share photos of the bride and groom, exchange anecdotes, and coordinate travel plans. There was even an obvious revenue model—link to hotels and gift-registeries and receive a commission on purchases. We could expand the site to other special events like reunions, golf-events, fund-raising walks, etc. The opportunities seemed wide open.

While I knew a little about programming a website, I didn’t know enough to do the whole thing. So I enlisted a partner to do the coding. The thing about coding is that even if you have a detailed specification, which we didn’t have, there are lots of decisions that get made on a regular basis that affect the final product. And every decision that the coder made was different from my vision. A lot of the things were things that just never occurred to the programmer. For example, if you have several pages on the site that start with a photo, they need to be in exactly the same place on every page. Otherwise when you move from page to page, the pages jump all over the place. And back then, most people were still using small monitors, so we couldn’t design a page that was wider than around 600 pixels or else people would have to scroll sideways to see it. Likewise, we needed to stick with a 65,536 color palette for most of the design. At the end I literally spent more time trying to persuade the coder to do things the way I wanted than they spent coding. I would have been better off spending the time learning how to code myself and then coding things the way they were supposed to be coded.

And I think that’s the difference between a coder and a hacker. The coder just wants to get the project done. The hacker wants to get it done right.

Since then, I have never let someone else be the coder on my projects. I will pay people to help me out when I am first learning a new language, but I do my own coding. And none of my projects have failed because they didn’t get built.

That’s not to say it couldn’t work. I can see how having a non-coding founder would be great for lots of startups, especially those that rely on face-to-face marketing or lots of back-end coordination with other businesses. But the kinds of startups that require a lot of coding seem to me to require hackers as founders.

Women as Founders

Paul Graham got a lot of flak recently for something he didn’t say about the ability of women to found startups.

We can’t make women look at the world through hacker eyes and start Facebook because they haven’t been hacking for the past 10 years.

As he explains, that didn’t sound like anything he’d say, and in fact is the opposite of what he thinks. The journalist neglected to put the quote in context and left our a crucial word. The actual quote was,

We can’t make these women look at the world through hacker eyes and start Facebook because they haven’t been hacking for the past 10 years.

And the question was about why his startup company couldn’t accept more women into their startup class and train them to be hackers. So he was answering a question about why it would be impossible in three months to turn someone who wasn’t a hacker into one. It had nothing to do with the skills of women hackers or really anything at all to do with women. It really had more to do with what makes a successful founder of a startup.

A lot of small software companies (some of which become large later) are founded by people who are “scratching their own itch”. They run across a problem in what they are doing and solve it. If they had the problem, odds are good that others did too, so they publicize their solution. There is a long history in the open software movement of doing just that. Many of the tools that programmers use every day are the result of sharing their solution with others. The web runs on Linux and the GNU tools and both were started by people who wanted to solve a problem that they had, and it turns out that others had the same problem and were interested in cooperating to solve it.

This hacker mindset is not something that can be taught in three months. I’ll give an example of what I’m talking about on a small scale. My server guy got a new job about a year ago. I know a little about server administration, but had to learn a lot more to keep them running. I got a bit of practice setting up a server when we moved ours from a dedicated server to a VPS. And then I set up one for my nephew. And started maintaining one for someone else. Now logging into a server isn’t hard, you use the command ssh loginid@servername and then type in your password at the prompt. And for my server it wasn’t hard since the commands were usually stored a few lines up in my history and so I just had to use a few up arrows to avoid typing. But with four servers to log into (two of which used numbers—not domain names) I had a harder time finding the lines in history and remembering the passwords for each site. And that’s where the hacker mindset comes in. The command line interface that I use is called bash and it lets you write login scripts and aliases. You can get really complicated with scripts, but I just wanted a shortcut to log in to my servers.

So I wrote an alias to get into my server, ¯server=’ssh loginid@192.168.194.220′, then all I had to do was type server and I could get into my server. And then I wrote an alias for each of the servers that I work on.

But if there is an update that needs to be applied on each server, I want to make sure I do it for each one, so I wrote a simple one that listed all of the servers and then I’d type in the number of the one I wanted to use. My command line prompt looked like this.


loginid@My-MacMini: ~ $ connect
1) server
2) dave
3) don
4) purple
5) Quit
Select a server. 

Then I set up each of the servers to use secure authorization, so that I didn’t have to type a password, it used a public-key encryption method to verify that I was allowed in.

Now when you are working on lots of servers, you sometimes forget where you are. So I decided use a different color prompts for each server. One looked like this: loginid@server: ~ $

I copied the login script to each of the servers and tested it out. I decided to make some changes and so I had to copy it to each of the servers again. That’s not especially efficient, so I wrote a script that I run when I make changes and it automatically pushes the script to each of the servers.

Here’s the part non-hackers don’t get. In order to save myself 30 seconds of typing a few times a week, I read a 300 page book about bash. I spent probably three days in total working examples and rewriting my script. I’ll probably never save three days worth of time. But now I have a new tool in my toolbox, that I can use to automate some processes—in fact I’m going to automate the process of updating WordPress blogs when I finish this post. And that’s what can’t be taught in three months.

Injection attacks revisited.

I thought I’d share another injection attack defense that I use on my sites. You can buy my stuff from Gumroad and I have a page where I list all of the Mac titles and a page where I list all of the Windows titles. I use one php script for both and there are only two choices for the page variable, ‘Mac’ or ‘Win’. It should’t happen but I allow for no values as well.


// I get the data for the page from a database, and you need one if you use 
// mysql_real_escape_string() so it goes first.
require_once('db_my.inc');

if ( isset($_GET['page']) ) { 
    $platform  = mysql_real_escape_string($_GET['page']); 
    
    // Platform can only be Mac or Win, so make injection attacks go away
    if ( strlen($platform) > 3 ) {
        $url = $_SERVER['REQUEST_URI'];
        $ref = $_SERVER['HTTP_REFERER'];
        error_log("long string in CDs.php: URL is $url and referrer is $ref");
        header("HTTP/1.0 404 Not Found");
        die();
    }

// If there is no $platform, they probably want to buy a title that works on 
// the platform they are visiting the site with
}  else { 
    $user_agent = $_SERVER['HTTP_USER_AGENT']; 
    $platform = 'Win'; // Default to windows
    if (preg_match('/macintosh|mac os x/i', $user_agent)) {
        $platform = 'Mac';
    }
}