SSL AWAY!

I finally got around to letsencrypt’s free SSL Certificate, as I might need it for future websites and I’d like to become familiar with it.

Before with my website I had to create a self-signed SSL certificate just to learn that. The only problem I had was with ssllabs and their “You get an A if you spend money…”, since my configuration was as tight as apache would allow me to make it.

So, I was able to get letsencrypt setup, my 90-day issued cert plugged in, and the renewal on a cron. It’s really easy if you follow the directions, of course.

And I’m okay with an SSLLabs rating of B, since i’m gonna blame Apache for not sending the full certificate chain that the PEM “seems” to contain. I just wanted my green bar and my https, and I got it.

I’m a happy guy today.,

apache process tuning

A long, long time ago I had an opportunity to fine-tune apache processes on a couple hundred hosts. It took one script run on some of the highly-loaded hosts to get specific numbers, and those numbers are what are important.

For shell processing you’ll need bc.

Running the below program on my current host presents the following output:

sudo ./apache_process_tuning.pl
1035:11956224 1036:19152896 1037:16871424 1038:32567296 1039:11386880 1040:13230080 1041:15876096 1042:20291584 2131:14344192 2132:14438400 2133:13373440 10578:15732736 29812:2068480
==========
There are 13 Apache Processes that consume 201,289,728 bytes of RAM
Each process takes an average of 15,483,825 bytes of RAM

You have 2,103,779,328 bytes of RAM, with 1,756,119,040 unused if Apache were not running

You can be ok with a MAX_CLIENTS setting lower than 113

To the gods of perl, I present thee!

#!/usr/bin/perl
use strict;
use warnings
# http://www.perlmonks.org/?node_id=110137
sub commify {
   my $text = reverse $_[0];
   $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
   return scalar reverse $text
}
# step 0, make sure we are sudo
die("Need to sudo this command") if ( not defined $ENV{'SUDO_USER'} );
# Step 1, get system memory information
my $free = `/usr/bin/free -mb`;
my ($mem_total, $mem_used, $mem_free);
for (split /^/, $free) {
   if ($_ =~ /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
      $mem_total = $1;
      $mem_used = $2;
      $mem_free = $3;
   }
}
die("Cannot get memory statistics") if (not defined $mem_total);
# Step 2, get httpd process
my $processes = `/bin/ps aux`;
my ($process_count, $process_total, $process_mem);
for (split /^/, $processes) {
   if ($_ =~ /(\w+)\s+(\d+)\s+[\d\.]+\s+[\d\.]+\s+\d+\s+\d+\s+[\w\?\/]+\s+[\w\+<]+\s+[\d\w:]+\s+[\d:]+\s+(.+)/) {
      my $proc_owner = $1;
      my $proc_pid = $2;
      my $proc_cmd = $3;
      if ($proc_cmd =~ /httpd$/) {
         # Step 2a, Get some Private_Dirty
         # http://stackoverflow.com/questions/118307/a-way-to-determine-a-processs-real-memory-usage-i-e-private-dirty-rss
         $process_mem = `awk '/Private_Dirty/ {print \$2,\$3}' /proc/${proc_pid}/smaps | sed 's/ tB/*1024 gB/;s/ gB/*1024 mB/;s/ mB/*1024 kB/;s/ kB/*1024/;1!s/^/+/;' | tr -d '\\n' | sed 's/\$/\\n/' | bc`;
         chomp($process_mem);
         $process_count++;
         $process_total+=$process_mem;
         print $proc_pid . ":" . $process_mem . " ";
      }
   }
}
die("Having a problem getting active httpd info") if (not defined $process_count);
# step 3, give some helpful output
my ($process_average, $unused_mem, $max_clients);
print "\n==========\n";
$process_average = sprintf("%d", $process_total / $process_count);
print "There are " . $process_count . " Apache Processes that consume " . commify($process_total) . " bytes of RAM\n";
print "Each process takes an average of " . commify($process_average) . " bytes of RAM\n";
print "\n";
$unused_mem = sprintf("%d", $mem_used - $process_total);
print "You have " . commify($mem_total) . " bytes of RAM, with " . commify($unused_mem) . " unused if Apache were not running\n";
print "\n";
# Math is: "available" RAM with no httpd divided by average process total
$max_clients = sprintf("%d", $unused_mem / $process_average);
print "You can be ok with a MAX_CLIENTS setting lower than " . $max_clients . "\n";
print "\n";

Upgrades and good grades

What is now:

 15:39:17 up  5:27,  1 user,  load average: 0.01, 0.04, 0.01

Ah, the uptime. One of the things we aspire to make as large as possible, and love every minute of it.

I did do a reboot today due to a mass of updates that I’ve lacked to do for 250+ days. Regardless, it’s a fresh uptime, and i’ll go with that.

With all these mass updates included SSL attacks such as poodle and heartbleed. I don’t typically run my server on https for public facing stuff, but right now I do for specific URLs and all that is presented is a self-signed certificate. You can go ahead and try https://www.unliterate.net to get the typical browser warnings.

So, with all the updates ssllabs SSL Server Test has given me a “T” (or A-), which I’m pretty proud of after reconfiguring. Maybe I’ll end up buying that cheap SSL cert and going for broke.

What used to be:

I happened to get really curious and find out if some old websites and documents existed from when I was originally fumbling around computers myself. Lo and behold, yes, I found ’em.

RBIL / Ralf Browns Interrupt List (wikipedia, cmu)

The de-facto bread and butter of my machine language learning. For every piece of hardware that downloaded its ROM into RAM, or any software that made hooks into the IVT, this list was just awesome.

I can’t recall how I located it back in the day, but what I do remember is that I was excited to get the updates to it online. Back in the modem days i’d wait upwards to 5 minutes to download 1 of the zip files, and then maybe an entire minute to load one of the text files into Windows 95’s notepad.

This list also got me into direct port access programming. Some of the interrupts and combinations needed for RS232 programming seemed slow to me, especially when trying to go faster than 9600 baud, so I had to turn to a different reference to learn to actually drive the serial controller.

Beyond Logic (retired)

Craig Peacock wrote awesome manuals on how to talk to the RS232 controller (specifically the 8250 and 16450/16550 UARTS), and also the Parallel Ports as well. It wasn’t until I read his manual about the parallel ports that realized that the bidirectional capability had quite a faster transfer rate over the cable than serial. His manuals helped deepened my knowledge on “how things worked”, cause who wouldn’t wanna know how things worked.

PHG Opcode (phg.chat.ru)

From Ralf Browns INTERRUP.LSTs came OPCODE.LST, which was a separate list created and maintained by Alex Potemkin. This list itself, when read entirely, gives you so much in-depth knowledge on how a processor works. From Intel and AMD, to Cyrix, you got instruction times, bugs, incompatibilities, and more than the whole nine yards. It was from this that I understood that 0F A2 means “Identity Yourself!”

From my memory this actually used to be at www.chat.ru/~phg, but as times change URLs have to change.

In a nutshell:

It’s been 20+ years that I’ve been using a keyboard and digging into computer guts, both software and hardware. I’ve been in and out of technology-related occupations, stepped into many hats, and accomplished so much, and I feel good about it.

Sometimes it feels good to take a step back and wonder how you got there, cause all you see is the progress you’ve had and know there is more to accomplish.

email.heick.email

Yays!

Today i’ve done it. I’ve acquired my email dream!

I’m talking about a nearly-automated @heick.email

…to explain…

For years, if you ever wanted to send me an email I would say:

“Just put your name at the front of @unliterate.net, and i’ll get it.”

Ever since I setup my email @unliterate.net wrong as a catch-all SPAM domain, I’ve had to deal with the following rigmarole when getting new email setup:

  1. Get the name@unliterate.net figured out
  2. Setup a folder in Thunderbird, my email client
  3. Setup a mail filter rule in my email client to move the received message from my Inbox to that folder

Which things have been working for years, and it’s been a fairly straightforward approach.

Until I got married, and we decided to get the heick.email domain and have all our mail shared.

…how to share the email…

So, the @unliterate.net experiment utilized POP3 as the server for me to get all my catch-all. This was easy to configure, and was fairly straightforward.

We needed to be able to share email across computers and devices, though, and still have the flexibility to do the “folder structure”-thingy that I’ve grown comfortable with the @unliterate.net “mail filter” rules.

So, the only solution is to go from POP3 to IMAP.

IMAP gives us the flexibility of folders on the server, not on the client. It also stores all the mail there, and the protocol (after swallowing that it’s not like POP3) is actually quite orderly and simple.

So, i’ve employed dovecot as my IMAP server, which was also my POP3 server, and configured it simply to enable IMAP and know where I want my users mailboxes to be stored.

After setting up DNS for mail, i’ve got email coming into @heick.email, and I’m happy.

I just need to be able to now do the mail filtering…

How to automate folder-making for IMAP

This was a basic challenge, and I love challenges.

I had to use my programming language of choice (PHP) with the php-imap module loaded, and fancy up a script that runs on a */1 (1 minute) cron task.

The script is as follows:

<?php
/**
 * The whole purpose of this script is to perform the following:
 * 1) Open an IMAP connection to an INBOX
 * 2) Look through all the messages
 * 3) Grab all messages and look for the first "To: " header in each message
 * 4) If the person in the "To: " is in the allowed domain
 * - We grab the user
 * - We check to see if their is a mailbox for that user, and move the messge there
 * - We delete the message
 * 5) If the person is not in the allowed domain
 * - We move the message to a default folder
 */

function get_imap_folders($resource, $config)
{
 // Get a list of mailboxes
 $original_folders = imap_listmailbox($resource, "{" . $config['server'] . ":" . $config['port'] . "}", "*");
 // these come through as {server:port}mailbox, so we just clean them up a bit
 $new_folders = array();
 $to_remove = "{" . $config['server'] . ":" . $config['port'] . "}";
 $folders = str_replace($to_remove, "", $original_folders);
 return $folders;
}

$config = array(
 'server' => 'localhost',
 'port' => '143',
 'username' => 'redacted',
 'password' => 'redacted',
 'folder' => 'INBOX',
 'spam' => 'SPAM',
 'debug' => true,
);
$debug_message = "";

$res = imap_open("{" . $config['server'] . ":" . $config['port'] . "/service=imap/novalidate-cert" . "}" . $config['folder'], $config['username'], $config['password']);
if (!$res)
{
 if ($config['debug'])
 {
 $debug_message = "IMAP Stream Failure";
 }
 die($debug_message);
}

$folders = get_imap_folders($res, $config);

// Lets get all the mail messages in the $config['folder']
$mbox = imap_check($res);
$number_messages = $mbox->Nmsgs;
if ($number_messages == 0)
{
 if ($config['debug'])
 {
 $debug_message = "No Messages";
 }
 die($debug_message);
}
$range = "1:" . $number_messages;

// now, we'll get the messages
$messages = imap_fetch_overview($res, $range);
foreach ($messages as $msg)
{
 $msgno = $msg->msgno;
 $to = $msg->to;

echo "Message: " . $msg->subject . "\n";
 if (strpos($to, "@"))
 {
 $array_to = explode("@", $to);
 $to = $array_to[0];
 }

// do we need to create a folder to move this message into?
 $destination_mbox = "{" . $config['server'] . ":" . $config['port'] . "}" . $to;
 if (!in_array($to, $folders))
 {
 if (imap_createmailbox($res, $destination_mbox))
 {
 echo "> Created folder [$to]\n";
 }
 else
 {
 echo "> Failed to create folder [$to]\n";
 }

}
 $folders = get_imap_folders($res, $config);
 if (imap_mail_move($res, $msgno, $to))
 {
 echo "+ Moved successfully\n";
 }
 else
 {
 echo "- Failed to move message\n";
 }
}
imap_expunge($res);
imap_close($res);
?>

To explain, basically this access my IMAP server, gets all the folders, then gets all the mail. It goes though the “to:” portions of the email addresses and sees if I have a folder that matches what’s in the name part of the email address in the “to:” portion. If it doesn’t exist, it makes the folder. Then, as a final result, it moves the mail to that folder and aborts.

So, this script now runs every minute, checking for new mail, creating the folders necessary and moving the messages.

vivre heick.email!

How to build an RPM from scratch with Centos 6.8

I’ve been completely curious on how to actually build an RPM for Redhat/Centos from since…well, I knew they existed. There are many articles out there on the interwebs, but I felt it necessary to dig on out and get it going from conception to death.

Virtual Hardware and Software:

To start, i’m gonna use Oracle VM Virtualbox (currently at 5.0.26 r108824) and a Centos 6.8 Minimal install. What better way to start this than from nothing.

I created the VM with 1GB of RAM and the standard 8GB Virtual Hard Drive. Made some minor modifications to the VM such as:

  • Disabled the Audio
  • Enabled NIC1 and bridged it to my Ethernet Adapter
  • Disabled the USB Controller

I mounted the ISO and booted it up for the install.

Operating System Installation:

Clicking Start >, I skipped media testing and sailed into Anaconda. I accepted all default options except for allowing my Network Interface to be configured On and DHCP enabled. This saves me configuration options later on for /etc/sysconfig/networking-scripts and /etc/resolv.conf. Made roots password, well, password, since i’ll be sudo’ing a user for good measure. 205 packages later I have my system ready to be SSH’d into.

First Boot:

Once everything was installed and configured from Anaconda there was a bit of cleanup I like to do. It’s not required on every installation, but it helps me do things in my development environments without issues later on.

More updates:

At the time of this writing, with a fresh ISO you still need to belt out a yum upgrade. There exists 1 package to install, 27 to upgrade, and 76M of data to download. Best to get this out of the way before changing system configurations and having them reset back to basics. shutdown -r now, and we’re back in business.

Disabling selinux:

Fairly easy to do, and there is a plethora of documents on the interwebs to do it. All done as root:

vi /etc/selinux/config
SELINUX=permissive

Firing the firewall:

Cleanly shutting off iptables just helps in debugging local and remote connection issues. Good thing we won’t come into this with making our RPMs, but I might want to use this development machine later on and I don’t want to have to assume I did it when debugging issues. All done as root:

service iptables save
service iptables stop
chkconfig iptables off

Making myself useful:

Still have to do the basic administration, and create my user and give it some god-like sudo permissions:

adduser mheick
passwd mheick
visudo
mheick ALL=(ALL) ALL

Finally, we do some minor shell-related things like setting our TERM=xterm-256color and finding out our ip address so we can SSH into it to get this party started.

Finding and following instructions:

So, we need a couple things that do not come with the minimum install to prepare for this journey:

1 – We need a user that we will /use/ to build things with. We’re gonna create one called builder:

sudo adduser robertbuilder
sudo passwd robertbuilder

2 – We are going to need rpm-build, devtools and their dependencies:

sudo yum install rpm-build rpmdevrools

Our data:

We’re gonna be a good sport and create some test data, and go ahead and tar it up:

mkdir data
chdir data
touch main
touch final
touch one
tar -czf myfirstrpm.tar.gz

This creates myfirstrpm.tar.gz, which we will use to extract these junky files somewhere.

Before making a .spec file, we must be prepared:

The heart and soul of an RPM is this specific file. It contains all the instructions on /what/ to do with the contents of the RPM, where to install things, what to say, etc. We’re going to start off getting our RPM over in robertbuilder‘s home folder, passing along ownership, and then becoming robertbuilder to continue on.

sudo cp myfirstrpm.tar.gz /home/robertbuilder/
sudo chown robertbuilder:robertbuilder /home/robertbuilder/myfirstrpm.tar.gz
sudo su robertbuilder

Our builder user needs a folder structure in order to store our files, test out our RPMs, store our other files, and do testing and funsies. We use what we’re given.

rpmdev-setuptree

This creates the ~/rpmbuild/(BUILD|RPMS|SOURCES|SPECS|SRPMS) folders so that we can actually make this build happen.

Getting the .spec into it

We need to hope into the ~/rpmbuild/SPECS folder and execute our spec-template creator

rpmdev-newspec myfirstrpm

This creates a basic .spec:

Name: myfirstrpm
Version:
Release: 1%{?dist}
Summary:

Group:
License:
URL:
Source0:

BuildRequires:
Requires:

%description


%prep
%setup -q


%build
%configure
make %{?_smp_mflags}


%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT


%clean
rm -rf $RPM_BUILD_ROOT


%files
%defattr(-,root,root,-)
%doc

%changelog

We’re going to modify lines in that so that we can properly install our myfirstrpm.tar.gz

Now, we need HAAAALP!:

No worries. We have centos.org documentation!