Linux Today: Linux News On Internet Time.
Search Linux Today
search.internet.com
Linux News Sections:  Blog -  Developer -  High Performance -  Infrastructure -  IT Management -  Security -  Storage -
Linux Today Navigation
LT Home
Preferences
Contribute
Link to Us
Search
Linux Jobs

Become a Marketplace Partner

internet.commerce
Be a Commerce Partner














The Linux Channel at internet.com
Linux Today
Enterprise Linux Today
Apache Today
JustLinux.com
Linux Planet
PHPBuilder
All Linux Devices
Technology Jobs

JustTechJobs.com

LinuxToday Newsletters
Subscribe News
Subscribe PR
Subscribe Security

internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

 







Current Newswire:

Linux Evolution Reveals Origins of Curious Mathematical Phenomenon

A Microsoft Veteran Embraces Open Source

Using Spawner To Populate SQL Database

WiMAX Deal "Clears" Linux for Takeoff

Nitrogen: A Background Setter For Lightweight Desktop Manager

Technology, Innovation and the Challenge of the Missing Standards

Red Hat Chief: 'Cheaper Generally Wins'

How Comcast Controls Sony's Internet TV Plans

Growth in Internet Crime Calls for Growth in Punishment

10 of the Best Songbird Add-ons




Unix/Red Hat Systems Adminsitrator
The Computer Merchant, Ltd
US-PA-Lansdale

Justtechjobs.com Post A Job | Post A Resume
:Laurent Constantin: Testing a router or firewall
Laurent Constantin: Testing a router or firewall
May 4, 2001, 18 :56 UTC (10 Talkback[s]) (18229 reads)

(Other stories by Laurent Constantin)

By Laurent Constantin

Testing a router or firewall


Introduction

The life of a router is punctuated by several important steps :
  • configuration
  • securing
  • problem resolution
  • rules modifications
  • replacement by a new router
In each case, network tests are needed to validate administrator's choices. For example :
  • verify the router is working as expected
  • verify an intruder cannot reach a given IP address or a forbidden port
  • solving a network problem to verify why an application isn't functioning
  • verify the validity of new rules
  • simulate a testing network to help configuring a new network device
The aim of this article is to present a method for testing routers and firewalls. In this document, we only use the term "router", but the described method can also be applied to stateful inspection firewalls, packet filtering firewalls, proxy firewalls, etc.

Basic idea

The basic idea about tests is to send a packet on one side of the router.
Then, on the other side :
  • if this packet is allowed, verify its arrival
  • if this packet is evil (deny, drop), verify nothing is forwarded
  • if this packet is blocked (reject), verify nothing is forwarded and an ICMP error message is sent back to sender (there is a rate limiting for ICMP)

Method

We do not present a generic high level method. Indeed, every network administrator has its own way to setup a device or to solve a problem.
We emphasis on the low level method by presenting key points, which can be linked together in order to construct the high level method of every person. The key points are :
  • How to send a packet ?
  • How to verify the arrival of a packet ?
  • How to simulate a testing computer ?
Using only these 3 key points, an administrator can test a network.

Tool used

In order to illustrate examples, the free network testing tool lcrzoex is used. Lcrzoex is available at :
http://www.laurentconstantin.com/us/lcrzo/ [main server]
http://go.to/laurentconstantin/us/lcrzo/ [backup server]
http://laurentconstantin.est-la.com/us/lcrzo/ [backup server]

Other tools or network libraries (tcpdump, snoop, ipsend, netcat, telnet, libnet, libpcap, etc.) can also be used, but I choose lcrzoex because it incorporates all we need in one program.

How to send a packet ?

Well, it depends on protocols supported by our network. For example, in this paper, we focus on IP over Ethernet, and ICMP/UDP/TCP.

Which kind of packets to send ?

The kind of sent packets depends on several factors :
  • Do we want to check an allowed, or a forbidden flow ?
    In the first case, we send a valid packet.
    In the second case, we send an invalid or forbidden packet.
  • Does the router is in a testing platform or in its real place ?
    In the second case, it might be dangerous to send invalid packets.
  • Does the sender and destination computers are available, or need to be simulated ?
    In the first case, we spoof at IP level.
    In the second case, we have to spoof at Ethernet level.
  • Etc.

What's the difference between IP level and Ethernet level ?

When a packet is sent at IP level, the local IP stack :
  • set the source Ethernet address to the MAC address of the network board
  • gets the Ethernet address of the router by sending an ARP request (or by looking in its local ARP cache)
So, the user doesn't have to bother with Ethernet. However, this method doesn't allow to do tricky stuff with Ethernet, and sometimes with IP itself because the sender IP stack rejects the packet.
When a packet is sent at Ethernet level, it is directly sent on the network without going through the IP stack. It is more complicated because the user has to set Ethernet addresses, but can allow to do tricky things. To obtain the Ethernet address of a computer on the LAN, use "lcrzoex 2" :
# lcrzoex 2 192.168.10.2
  ip address :       192.168.10.2
  ethernet address : 00:40:95:46:11:23
Don't forget that the destination Ethernet address has to be set to :
  • the Ethernet address of the router, if the destination IP address is not on the LAN
  • the Ethernet address of the destination IP address otherwise

How to send an ICMP packet at IP level ?

We can use "lcrzoex 65" :
# lcrzoex 65
source address [255.255.255.255]: 192.168.10.1
destination address [1.2.3.4]: 192.168.11.3
IP options []: 
type (between 0 and 255)[8]: 8
code (between 0 and 255)[8]: 0
packet's data ['hello' 0D 0A]: 12345678 'my data'

 IP______________________________________________________________________.
 |version |  ihl   |       tos       |              totlen               |
 |___ 4___|___ 5___|_______  0_______|____________0023h=  35_____________|
 |                id                 |xxDfMf         fragoffset          |
 |____________822Bh=33323____________|0_0_0__________0000h=   0__________|
 |       ttl       |    protocol     |          header checksum          |
 |_____80h=128_____|_____01h= 1_____|_______________235Ah________________|
 |                                source                                 |
 |______________________________192.168.10.1_____________________________|
 |                              destination                              |
 |______________________________192.168.11.3_____________________________|
 ICMP____________________________________________________________________.
 |      type       |      code       |             checksum              |
 |_____08h=  8_____|_____00h= 0_____|____________3F01h=16129_____________|
 12 34 56 78  6D 79 20 64  61 74 61                     # .4Vxmy data
The example 66 is identical, but takes its parameters from command line :
# lcrzoex 66 192.168.10.1 192.168.11.3 8 0

How to send an ICMP packet at Ethernet level ?

We can use "lcrzoex 68" :
# lcrzoex 68
send on which device [eth0]:
source address [aa:bb:cc:dd:ee:ff]: 00:40:33:E0:2C:42
destination address [ff:ff:ff:ff:ff:ff]: 00:40:95:46:41:BC
source address [255.255.255.255]: 192.168.10.1
destination address [1.2.3.4]: 192.168.11.3
IP options []: 
type (between 0 and 255)[8]: 8
code (between 0 and 255)[8]: 0
packet's data ['hello' 0D 0A]: 12345678 'my data'
 ETH_____________________________________________________________________.
 | 00:40:33:e0:2C:42 vers 00:40:95:46:41:BC         type : 0x0800        |
 |_______________________________________________________________________|
 IP______________________________________________________________________.
 |version |  ihl   |       tos       |              totlen               |
 |___ 4___|___ 5___|_______  0_______|____________0023h=   35____________|
 |                id                 |xxDfMf         fragoffset          |
 |____________F3D2h=62418____________|0_0_0__________0000h=    0_________|
 |       ttl       |    protocol     |          header checksum          |
 |_____80h=128_____|_____01h=  1_____|_______________B1B2h_______________|
 |                                source                                 |
 |______________________________192.168.10.1_____________________________|
 |                              destination                              |
 |______________________________192.168.11.3_____________________________|
 ICMP____________________________________________________________________.
 |      type       |      code       |             checksum              |
 |_____08h=  8_____|_____00h=  0_____|____________3F01h=16129____________|
 12 34 56 78  6D 79 20 64  61 74 61                     # .4Vxmy data
The example 69 is identical, but takes its parameters from command line :
# lcrzoex 69 eth0 00:40:33:E0:2C:42 00:40:95:46:41:BC 192.168.10.1 192.168.11.3 8 0

How to send an UDP packet at IP level ?

We can use "lcrzoex 37" :
# lcrzoex 37
source address [255.255.255.255]: 192.168.10.1
destination address [1.2.3.4]: 192.168.11.3
IP options []: 
source port (between 0 and 65535)[2345]: 1234
destination port (between 0 and 65535)[53]: 
packet's data ['hello' 0D 0A]: 
Do you want an Empty string or the Default string ? (key eEdD)[d]: 
 IP______________________________________________________________________.
 |version |  ihl   |       tos       |              totlen               |
 |___ 4___|___ 5___|_______  0_______|____________0023h=   35____________|
 |                id                 |xxDfMf         fragoffset          |
 |____________31C2h=12738____________|0_0_0__________0000h=    0_________|
 |       ttl       |    protocol     |          header checksum          |
 |_____80h=128_____|_____11h= 17_____|_______________73B3h_______________|
 |                                source                                 |
 |______________________________192.168.10.1_____________________________|
 |                              destination                              |
 |______________________________192.168.11.3_____________________________|
 UDP_____________________________________________________________________.
 |            source port            |         destination port          |
 |____________04D2h= 1234____________|____________0035h=   53____________|
 |              length               |             checksum              |
 |____________000Fh=   15____________|____________1795h= 6037____________|
 68 65 6C 6C  6F 0D 0A                                  # hello..
The example 38 is identical, but takes its parameters from command line :
# lcrzoex 38 192.168.10.1 192.168.11.3 1234 53

How to send an UDP packet at Ethernet level ?

We can use "lcrzoex 40" :
# lcrzoex 40
send on which device [eth0]: 
source address [aa:bb:cc:dd:ee:ff]: 00:40:33:E0:2C:42
destination address [ff:ff:ff:ff:ff:ff]: 00:40:95:46:41:BC
source address [255.255.255.255]: 192.168.10.1
destination address [1.2.3.4]: 192.168.11.3
IP options []: 
source port (between 0 and 65535)[2345]: 1234
destination port (between 0 and 65535)[53]: 
packet's data ['hello' 0D 0A]: 
Do you want an Empty string or the Default string ? (key eEdD)[d]: 
 ETH_____________________________________________________________________.
 | 00:40:33:e0:2C:42 vers 00:40:95:46:41:BC         type : 0x0800        |
 |_______________________________________________________________________|
 IP______________________________________________________________________.
 |version |  ihl   |       tos       |              totlen               |
 |___ 4___|___ 5___|_______  0_______|____________0023h=   35____________|
 |                id                 |xxDfMf         fragoffset          |
 |____________F2CBh=62155____________|0_0_0__________0000h=    0_________|
 |       ttl       |    protocol     |          header checksum          |
 |_____80h=128_____|_____11h= 17_____|_______________B2A9h_______________|
 |                                source                                 |
 |______________________________192.168.10.1_____________________________|
 |                              destination                              |
 |______________________________192.168.11.3_____________________________|
 UDP_____________________________________________________________________.
 |            source port            |         destination port          |
 |____________04D2h= 1234____________|____________0035h=   53____________|
 |              length               |             checksum              |
 |____________000Fh=   15____________|____________1795h= 6037____________|
 68 65 6C 6C  6F 0D 0A                                  # hello..
The example 41 is identical, but takes its parameters from command line :
# lcrzoex 41 eth0 00:40:33:E0:2C:42 00:40:95:46:41:BC 192.168.10.1 192.168.11.3 1234 53

How to send a TCP packet at IP level ?

We can use "lcrzoex 48" :
# lcrzoex 48
source address [255.255.255.255]: 192.168.10.1
destination address [1.2.3.4]: 192.168.11.3
IP options []: 
source port (between 0 and 65535)[2345]: 1234
destination port (between 0 and 65535)[53]: 80
bit syn (between 0 and 1)[0]: 1
bit ack (between 0 and 1)[0]: 
bit rst (between 0 and 1)[0]: 
seqnum (between 0 and 4294967295)[3145138187]: 
acknum (between 0 and 4294967295)[2039479918]: 0
TCP options []: 
packet's data ['hello' 0D 0A]:
Do you want an Empty string or the Default string ? (key eEdD)[d]: e
 IP______________________________________________________________________.
 |version |  ihl   |       tos       |              totlen               |
 |___ 4___|___ 5___|_______  0_______|____________0028h=   40____________|
 |                id                 |xxDfMf         fragoffset          |
 |____________344Eh=13390____________|0_0_0__________0000h=    0_________|
 |       ttl       |    protocol     |          header checksum          |
 |_____80h=128_____|_____06h=  6_____|_______________712Dh_______________|
 |                                source                                 |
 |______________________________192.168.10.1_____________________________|
 |                              destination                              |
 |______________________________192.168.11.3_____________________________|
 TCP_____________________________________________________________________.
 |            source port            |         destination port          |
 |____________04D2h= 1234____________|____________0050h=   80____________|
 |                                seq num                                |
 |_________________________BB77000Bh=3145138187__________________________|
 |                                ack num                                |
 |_________________________00000000h=         0__________________________|
 |dataoff |         . . UrAk PuRsSyFi|               window              |
 |___ 5___|___ 0____0_0_0_0__0_0_1_0_|____________05DCh= 1500____________|
 |             checksum              |          urgent pointer           |
 |____________DC0Eh=56334____________|____________0000h=    0____________|
The example 49 is identical, but takes its parameters from command line :
# lcrzoex 49 192.168.10.1 192.168.11.3 1234 80 1 0 0 2222222 0

How to send a TCP packet at Ethernet level ?

We can use "lcrzoex 51" :
# lcrzoex 51
send on which device [eth0]: 
source address [aa:bb:cc:dd:ee:ff]: 00:40:33:E0:2C:42
destination address [ff:ff:ff:ff:ff:ff]: 00:40:95:46:41:BC
source address [255.255.255.255]: 192.168.10.1
destination address [1.2.3.4]: 192.168.11.3
IP options []: 
source port (between 0 and 65535)[2345]: 1234
destination port (between 0 and 65535)[53]: 80
bit syn (between 0 and 1)[0]: 1
bit ack (between 0 and 1)[0]: 
bit rst (between 0 and 1)[0]: 
seqnum (between 0 and 4294967295)[4293488417]: 
acknum (between 0 and 4294967295)[1610530550]: 0
TCP options []: 
packet's data ['hello' 0D 0A]:
Do you want an Empty string or the Default string ? (key eEdD)[d]: e
 ETH_____________________________________________________________________.
 | 00:40:33:e0:2C:42 vers 00:40:95:46:41:BC         type : 0x0800        |
 |_______________________________________________________________________|
 IP______________________________________________________________________.
 |version |  ihl   |       tos       |              totlen               |
 |___ 4___|___ 5___|_______  0_______|____________0028h=   40____________|
 |                id                 |xxDfMf         fragoffset          |
 |____________113Dh= 4413____________|0_0_0__________0000h=    0_________|
 |       ttl       |    protocol     |          header checksum          |
 |_____80h=128_____|_____06h=  6_____|_______________943Eh_______________|
 |                                source                                 |
 |______________________________192.168.10.1_____________________________|
 |                              destination                              |
 |______________________________192.168.11.3_____________________________|
 TCP_____________________________________________________________________.
 |            source port            |         destination port          |
 |____________04D2h= 1234____________|____________0050h=   80____________|
 |                                seq num                                |
 |_________________________FFE96F21h=4293488417__________________________|
 |                                ack num                                |
 |_________________________00000000h=         0__________________________|
 |dataoff |         . . UrAk PuRsSyFi|               window              |
 |___ 5___|___ 0____0_0_0_0__0_0_1_0_|____________05DCh= 1500____________|
 |             checksum              |          urgent pointer           |
 |____________A084h=41092____________|____________0000h=    0____________|
The example 52 is identical, but takes its parameters from command line :
# lcrzoex 52 eth0 00:40:33:E0:2C:42 00:40:95:46:41:BC 192.168.10.1 192.168.11.3 1234 80 1 0 0 2222222 0

How to verify the arrival of a packet ?

To check if a packet arrives on a network, we have to use a sniffer. We might however encounter problems :
  • if the sniffer is on the destination computer, everything should be fine
  • if the sniffer is on the way to the destination computer (on a crossed router), everything should be fine
  • if the sniffer is on the same LAN than the destination computer (or if the sniffer is on a crossed LAN) :
    • if the LAN isn't switched, everything should be fine
    • else, we have to connect the sniffer on a dedicated port of the switch (or saturate the switch)
  • else, there is no way to see the packet

To display packets "lcrzoex 7" can be used :
# lcrzoex 7
Choose the print profile
  1 - header and data in synthetic aspect
  2 - header (without ethernet) and data in synthetic aspect
  3 - header and data in array aspect
  4 - header in array aspect and data in dump
  5 - header in array aspect and data in mixed
  6 - header and data in hexa aspect
  7 - header in hexa aspect and data in dump
  8 - header in hexa aspect and data in mixed
  9 - personnalized profile
Choose the profile (between 1 and 9)[4]: 4
 ETH_____________________________________________________________________.
 | 00:40:33:e0:c2:24 vers 00:40:95:46:14:cb         type : 0x0800        |
 |_______________________________________________________________________|
 IP______________________________________________________________________.
 |version |  ihl   |       tos       |              totlen               |
 |___ 4___|___ 5___|_______  0_______|____________0054h=   84____________|
 |                id                 |xxDfMf         fragoffset          |
 |____________0052h=   82____________|0_0_0__________0000h=    0_________|
 |       ttl       |    protocol     |          header checksum          |
 |_____40h= 64_____|_____01h=  1_____|_______________E502h_______________|
 |                                source                                 |
 |______________________________192.168.10.1_____________________________|
 |                              destination                              |
 |______________________________192.168.10.3_____________________________|
 ICMP____________________________________________________________________.
 |      type       |      code       |             checksum              |
 |_____08h=  8_____|_____00h=  0_____|____________AA90h=43664____________|
 A1 02 00 00  7B D7 E1 3A  61 57 03 00  08 09 0A 0B     # ....{..:aW......
 0C 0D 0E 0F  10 11 12 13  14 15 16 17  18 19 1A 1B     # ................
 1C 1D 1E 1F  20 21 22 23  24 25 26 27  28 29 2A 2B     # ...~ !"#$%&'()*+
 2C 2D 2E 2F  30 31 32 33  34 35 36 37                  # ,-./01234567

Various displaying methods can be selected (choice 1 to 9).

How to simulate a testing computer ?

When computer A wants to reach computer B :
  • computer A sends an ARP request to every computer on the LAN (it ask "what's the Ethernet address of B")
  • computer B sees this request and answer saying "the Ethernet address of B is aa:bb:cc:dd:ee:ff"
  • now computer A knows the Ethernet address of B, and can send IP packets to B

So, when we simulate a computer, we have to answer to ARP requests, in order to inform other computers. For example, to simulate the presence of 192.168.10.2, and saying its Ethernet address is 12:34:56:78:90:ab, we can use :
# lcrzoex 131 eth0 12:34:56:78:90:ab 192.168.10.2

First example

In this example, we want to verify that :
  • the sender 192.168.10.1 can go through
  • the router (192.168.10.254 and 192.168.11.254) to reach
  • the tcp port 80 of 192.168.11.3
Both 192.168.10.1 and 192.168.11.3 are "real" computers (we do not have to simulate them)

So, the testing procedure is :
  • on 192.168.11.3 : sniff with "lcrzoex 7"
  • on 192.168.10.1 : send a SYN with "lcrzoex 49 192.168.10.1 192.168.11.3 1234 80 1 0 0 2222222 0"
  • on 192.168.11.3 : we should see the packet

Second example

In this example, we want to verify that :
  • the sender 192.168.10.1 can go through
  • the router (192.168.10.254 and 192.168.11.254) to reach
  • the tcp port 80 of 192.168.11.4
The computer 192.168.10.1 is "real" and 192.168.11.4 is simulated with Ethernet address 12:34:12:34:12:34. So, the testing procedure is :
  • on 192.168.11.3 : sniff with "lcrzoex 7"
  • on 192.168.11.3 : simulate 192.168.11.4 with "lcrzoex 131 eth0 12:34:12:34:12:34 192.168.11.4"
  • on 192.168.10.1 : send a SYN with "lcrzoex 49 192.168.10.1 192.168.11.4 1234 80 1 0 0 2222222 0"
  • on 192.168.11.3 : we should see the packet for 192.168.11.4

Third example

In this example, we want to verify that :
  • the sender 192.168.10.2 can go through
  • the router (192.168.10.254 and 192.168.11.254) to reach
  • the tcp port 80 of 192.168.11.3
The computer 192.168.10.2 is simulated with Ethernet address 12:34:12:34:12:34. The computer 192.168.11.3 is real. So, the testing procedure is :
  • on 192.168.10.1 : obtain the Ethernet address of 192.168.10.254 with "lcrzoex 2 192.168.10.254" (for example, we obtain aa:aa:aa:aa:aa:aa)
  • on 192.168.11.3 : sniff with "lcrzoex 7"
  • on 192.168.10.1 : send a SYN with "lcrzoex 52 eth0 12:34:12:34:12:34 aa:aa:aa:aa:aa:aa 192.168.10.2 192.168.11.3 1234 80 1 0 0 2222222 0"
  • on 192.168.11.3 : we should see the packet

Other examples

Several other examples could be written using the same methods. This is left as an exercise for the reader.

Conclusion

Validating the configuration of a router is a long task, mainly if we want to verify the security of the device. The knowledge of key points, and the usage of generic tools can however simplify administrators' job. This paper only described the tests which can be done. Using these tests and they knowledge, administrators can elaborate their own method to configure or secure a router or a firewall.


Index Mode   |   Flat Mode   |   Thread Mode   |   Thread Flat  
  Talkback(s) Name  and Date
I would like to see more articles like t ...   More like this   
Photon Ghoul
May 4, 2001, 19:21:06
 
> I would like to see more articles like ...   Re: More like this   
Tom Dooley
May 4, 2001, 19:24:52
 
> More technology articles and less poli ...   Re: Re: More like this   
Bah
May 4, 2001, 20:40:00
 
I agree, we need more articles with some ...   Re:Re:Re: More like this   
dc
May 5, 2001, 03:44:39
 
Yes, i agree more technical stu......... ...   Tech-info.   
Mo
May 5, 2001, 16:50:46
 
Nice Tutorial please
Keep going
sw00w
 ...   Nice very Nice   
sw00w
Oct 26, 2001, 13:49:20
 
hi there i want to aske you some quistio ...   aske   
mahmoud
Mar 4, 2002, 13:09:19
 
Bravo Laurent,  cet article est super !C ...   Bravo   
Max
Oct 10, 2003, 04:44:43
 
I would like to know more on linux route ...   More on router testing   
chandrasekar
Aug 31, 2004, 07:07:32
 
I was searching for the stuff like this  ...   Gr8 stuff   
kkhanal
Mar 28, 2005, 04:44:54
 
  Home | Search Talkbacks | Customize View    Top of Page  



Enter your comments below:

* Your Name:

* Your Email Address:

* Subject:

CC: [will also send this talkback to an E-Mail address]

* Comments:

Tags allowed:<I>,<B> and <U>. See our talkback-policy for more about talkback content.

Fields marked with * are required!






..............................




All times are recorded in UTC.
Linux is a trademark of Linus Torvalds.
Powered by Linux, Apache and PHP

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Whitepapers and eBooks

Symantec Whitepaper: Converging System and Data Protection for Complete Disaster Recovery
Intel Whitepaper: Comparing Two- and Four-Socket Platforms for Server Virtualization
IBM Solutions Brief: Go Green With IBM System xTM And Intel
HP eBook: Simplifying SQL Server Management
IBM Contest: Are You the Next Superstar? Join the "Search for the XML Superstar" Contest to Find Out
Intel PDF: Quad-Core Impacts More Than the Data Center
Intel PDF: Virtualization Delivers Data Center Efficiency
Go Parallel Article: PDC 2008 in Review
Avaya Article: Communication-Enabled Mashups: Empowering Both Business Owners and IT
Intel Whitepaper: Building a Real-World Model to Assess Virtualization Platforms
PDF: Intel Centrino Duo Processor Technology with Intel Core2 Duo Processor
Microsoft Article: Build and Run Virtual Machines with Hyper-V Server 2008
  Go Parallel Article: Q&A with a TBB Junkie
IBM Whitepaper: Innovative Collaboration to Advance Your Business
Internet.com eBook: Real Life Rails
IBM eBook: The Pros and Cons of Outsourcing
Internet.com eBook: Best Practices for Developing a Web Site
IBM CXO Whitepaper: The 2008 Global CEO Study "The Enterprise of the Future"
Avaya Article: Call Control XML in Action - A CCXML Auto Attendant
IBM CXO Whitepaper: Unlocking the DNA of the Adaptable Workforce--The Global Human Capital Study 2008
Adobe Acrobat Connect Pro: Web Conferencing and eLearning Whitepapers
Symantec Whitepaper: Comprehensive Backup and Recovery of VMware Virtual Infrastructure
MORE WHITEPAPERS, EBOOKS, AND ARTICLES