TOC PREV NEXT

5.4 NETWORKING IN LINUX


Configuration files are under /etc

Recompile kernel in some cases, such as a firewall. or new hardware

Loadable modules

DHCP versus static IP

Most modern versions of Linux simplify hardware detection and setup. The steps below can help perform the basic operations, or find problems.

A. Installing a normal ethernet network connection:

1. During the installation process you will be asked for network parameters.
2. Enter a unique name for the machine and the network name.
3. (for DHCP) All that should be required is a setting for DHCP.
3. (for a static IP) You will need to enter the static IP number for the machine, as well as a netmask and gateway. If you are connecting to another network you can get these from a network administrator. If you are connecting your own network (not on the Internet) you can simply pick values like those below. Note that you need some sort of network router with an IP address of 192.168.1.254 for this to work.
IP address: 192.168.1.20
netmask: 255.255.255.0
Gateway: 192.168.1.254
nameserver: none

B. Troubleshooting an ethernet connection to the Internet,

1. Check to see if the network card is recognized with 'more /proc/modules' The card should be in the list. If not the kernel module must be installed.
2. Check to see if the network is setup with ifconfig. You should see 'eth0' or something similar. If it is not setup, the network parameters must be checked.
3. Check to see if the network is connected properly with ping to the local gateway, or another local machine - use the IP number, not the name. For example, 'ping 148.61.104.254'. If this fails the gateway or broadcast addresses are probably incorrect.
4. Check the connection to the outside with a ping such as 'ping 148.61.1.10'. If this is not allowed there is probably a problem with the outside connection
5. Verify that the nameserver is working alright with a ping to a named machine such as, 'ping www.linux.org'.
6. If all of these things work the network connection should be alright.

C. Installing a dialup connection

1. During the installation make sure that the location of your modem is correctly identified. Note: Winmodems are very popular because of their low cost, but there are very few Linux drivers. But... you are advised to spend the money for a non-Winmodem anyway, they are more reliable and they don't use your computers resources.
2.

D. Troubleshooting a dialup connection

1. Use a terminal program to dial the Internet service provider's number manually. If you don't get a response there is a problem with the modem installation.
2. After connected try providing your login ID and password and see if you get in. Expect to see garbage after this. If login is refused you need to check the user ID and password again.
3. Check ...

E. Setting up a firewall (this requires some work)

1. To set up a firewall the kernel must be recompiled to include network options such as multicasting, and firewall services.
[KERNEL OPTIONS]
2. Shut down the computer and add a second network card in the machine and reboot.
3. Check to see if the card is recognized with 'more /proc/modules'. Both ethernet cards should be listed. If not you will need to edit the network startup files. These are normally in '/etc/...' or for slackware '/etc/rc.d'. An example file follows. Reboot and check for both network cards again.
[NETWORK CONFIG FILES]
4. Use 'ipchains' to add services to pass, and modify the 'hosts.allow' and 'hosts.deny' files to control access.
[ipchains file declarations]
[hosts.allow file]
[hosts.deny file]

5.4.1 Network Programming in Linux

The following listings show network usage in Linux. The general method of network connection is different for servers and clients.

For servers.....

For clients....

Listing X.1 - network_io.cpp

#include "network_io.h"

#include <sys/poll.h>
#include <sys/ioctl.h>
#include <linux/tcp.h>

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>


network_io::network_io(){
type = _READ;
level = 0;
}


network_io::~network_io(){
if(type == _READ){
if(level > 1){
if(level > 2){
end_read_connection();
}
deinit_read();
}
} else if (type == _WRITE){

}
}


int network_io::set_remote_host(char *_host_name, int host_socket){
static int error;
static int nm_a,
nm_b,
nm_c,
nm_d;
struct hostent *hp;
unsigned char address[4];

error = NO_ERROR;
strcpy(host_name, _host_name);
host_socket_number = host_socket;

// Set up server descriptor, get host reference and error trap
write_connection.sin_family = AF_INET;
if((host_name[0] > '9') ||(host_name[0]<'0')){
hp = gethostbyname(host_name);
} else {
sscanf(host_name, "%d.%d.%d.%d",
&nm_a, &nm_b, &nm_c, &nm_d);
address[0] = (unsigned char)(nm_a);
address[1] = (unsigned char)(nm_b);
address[2] = (unsigned char)(nm_c);
address[3] = (unsigned char)(nm_d);
hp = gethostbyaddr((char *)address, 4, AF_INET);
}

if(hp != 0){
/* complete descriptor set up. */
bcopy((char *)hp->h_addr,
(char *)&(write_connection.sin_addr),
hp->h_length);
} else {
error_log(MINOR, "ERROR: unknown network host");
error = ERROR;
}

return error;
}


int network_io::set_local_host(int socket_num){
static int error;

error = NO_ERROR;
socket_number = socket_num;

return error;
}




int network_io::writer(char *string){
static int error;

error = NO_ERROR;

// Open a new socket for the write, and check for errors.
error = init_write();
if(error == NO_ERROR) error = open_write_connection();
if(error == NO_ERROR) error = write_to_connection(string);
if(error == NO_ERROR) error = end_write_connection();
if(deinit_write() == ERROR) error = ERROR;

return(error);
}



int network_io::reader(char *buf, int length){
static int error; // Error return variable

error = NO_ERROR;

// Wait for a socket connection request, then get its reference.
buf[0] = 0;
if(wait_read_connection() == NO_ERROR){
if(read_from_connection(buf, length) == ERROR){
}
// Close socket connection to remote write client.
end_read_connection();
}

return(error);
}


int network_io::init_write(){
static int error;
struct hostent *gethostbyname();

error = NO_ERROR;
/* Open a new socket for the write, and check for errors. */
if((rw_socket = socket(AF_INET, SOCK_STREAM, 0)) >= 0){
write_connection.sin_port = htons(host_socket_number);
} else {
error_log(MINOR, "ERROR: opening stream socket");
error = ERROR;
}

return error;
}


int network_io::open_write_connection(){
static int error;

error = NO_ERROR;
if(connect(rw_socket, (struct sockaddr *) &(write_connection), sizeof(write_connection)) < 0){
error = ERROR;
error_log(MINOR, "ERROR: Connecting stream Socket");
}

return error;
}


int network_io::write_to_connection(char *text){
static int error;

error = NO_ERROR;
if(write(rw_socket, text, strlen(text) /* +1 */) < 0){
error_log(MINOR, "ERROR: writing on stream socket");
error = ERROR;
}

return error;
}


int network_io::write_stuff_done(){
int error;

error = NO_ERROR;
return error;
}


int network_io::check_connection(){
int error;
int count;
struct pollfd ufds;

error = NO_ERROR;
ufds.fd = rw_socket;
ufds.events = POLLOUT | POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
count = poll(&ufds, 1, 0);
if((ufds.revents & 16) != 0) error = ERROR;

return error;
}


int network_io::end_write_connection(){
static int error;

error = NO_ERROR;

return error;
}


int network_io::deinit_write(){
static int error;

error = NO_ERROR;
close(rw_socket);
rw_socket = ANY;

return error;
}


int network_io::init_read(){
static int error; // low level socket number
unsigned length; // temporary work variable
static struct sockaddr_in server; // read socket descriptor
static struct hostent *hp;
char text[100];

// Open internet socket, and check for error.
error = ERROR;
gethostname(text, 100); /* who are we? */
hp = gethostbyname(text);
if((hp != NULL) && (read_socket = socket(AF_INET, SOCK_STREAM, 0)) >= 0){
// Set up server descriptor for binding name.
memset(&server, 0, sizeof(struct sockaddr_in));
server.sin_family = hp->h_addrtype;
server.sin_port = htons(socket_number);
// Bind the socket, and check for error.
level = 1;
int flag = 1;
setsockopt(read_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(int));
if(bind(read_socket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) >= 0){

// Check for valid socket binding
length = sizeof(server);
if(getsockname(read_socket, (struct sockaddr *)&server, &length) >= 0){
error = NO_ERROR;
// Set up variables for success
// Zero because anything higher would allow
// messages to arrive out of sequence.
listen(read_socket, 0);
} else {
error_log(MINOR, "ERROR: getting socket name");
}
} else {
error_log(MINOR, "ERROR: binding stream socket");
}
} else {
error_log(MINOR, "ERROR: opening stream socket");
}

return(error);
}


int network_io::read_stuff_waiting(){
int error,
count;
struct pollfd ufds;

error = ERROR;
ufds.fd = read_socket;
ufds.events = POLLIN | POLLPRI | POLLOUT;
count = poll(&ufds, 1, 0);
if((ufds.revents & 1) > 0){
error = NO_ERROR;
}

return error;
}


int network_io::wait_read_connection(){
static int error;
unsigned size;
static struct sockaddr addr;

error = NO_ERROR;
size = sizeof(struct sockaddr);
fcntl(read_socket, F_SETFL, O_NONBLOCK);
rw_socket = accept(read_socket, &addr, &size);

level = 2;
if(rw_socket < 0){
error = ERROR;
// error_log("ERROR: warning:accept");
}

return error;
}


int network_io::read_from_connection(char *buf, int length){
int error;
int len;

error = NO_ERROR;
// Empty input buffer
buf[0] = 0;
// Read string into buffer from socket
fcntl(rw_socket, F_SETFL, O_NONBLOCK);
len = read(rw_socket, buf, length);
if(len < 0){
// error_log("ERROR: reading stream message");
// error = ERROR;
if(errno != 11){
printf("errno=%d ", errno);
}
} else {
buf[len] = 0;
}

return error;
}


int network_io::end_read_connection(){
int error;
int a;

error = NO_ERROR;
a = close(rw_socket);
level = 1;

return error;
}


int network_io::deinit_read(){
int error;
int a;

error = NO_ERROR;
a = close(read_socket);
level = 0;

return error;
}


char *network_io::get_address(){
static char work[MAXIMUM_HOST_NAME_LENGTH];
struct sockaddr_in address;
int i,
addr[4];
long int_address;
#ifndef SGI
// Sun Version
get_myaddress(&address);
int_address = address.sin_addr.s_addr;
#else
// SGI Version
int_address = gethostid();
#endif
// SUN & SGI version
for(i = 0; i < 4; i++){
addr[i]=int_address & 0xFF;
int_address >>= 8;
}
#ifdef OTHER_UNIX
sprintf(work, "%d.%d.%d.%d",
(int)addr[3], (int)addr[2], (int)addr[1], (int)addr[0]);
#else
// This is for linux
sprintf(work, "%d.%d.%d.%d",
(int)addr[0], (int)addr[1], (int)addr[2], (int)addr[3]);
#endif
return work;
}


char *network_io::get_remote_client(){
staticchar work[100];
struct sockaddr address;
socklen_t len;

len = sizeof(address);
if(getpeername(rw_socket, &address, &len) == 0){
sprintf(work, "%u.%u.%u.%u", address.sa_data[2], address.sa_data[3], address.sa_data[4], address.sa_data[5]);
// printf("Got address [%s]\n", work);
//strcpy(work, address);
} else {
strcpy(work, "unknown network address");
}

return work;
}

Listing X.2 - network_io.h

#ifndef _NETWORK_IO
#define _NETWORK_IO


#include <errno.h>
#include <linux/socket.h> // sys/socket.h may be needed here
#include <sys/types.h>
#include <netdb.h>
#include <rpc/rpc.h>
#include <unistd.h>


#define ANY 0 // Indicates no socket number prechosen


#define MAXIMUM_HOST_NAME_LENGTH 100
class network_io{
public:
int socket_number;
int rw_socket;
// int read_connection;
char host_name[MAXIMUM_HOST_NAME_LENGTH];
int host_socket_number;
int read_socket;
struct sockaddr_in write_connection;
// char incoming_string[MAXIMUM_STRING_SIZE];

int type;
int level;
#define _READ 200
#define _WRITE 201
network_io();
~network_io();
int set_remote_host(char*, int);
int set_local_host(int);
int reader(char*, int);
int writer(char*);
int init_write();
int open_write_connection();
int write_to_connection(char*);
// int write_to_read_connection(char*);
int end_write_connection();
int deinit_write();
int init_read();
int wait_read_connection();
int read_from_connection(char*, int);
// int read_from_write_connection(char*, int);
int end_read_connection();
int deinit_read();
int read_stuff_waiting();
int write_stuff_done();
int check_connection();
char* get_remote_client();

char *get_address();
};

#endif

Listing X.3 - network.cpp

#include "../network_io/network_io.h"
#include <time.h>


network_io *network;
int mode;
char *params;
char received_temp[200];
int connect_flag;
time_t now_time;
time_t last_time;
int timeout;


int main(){
timeout = 5; // the default timeout

return 1;
}


int deinit(){
int error;

error = NO_ERROR;
if(network != NULL) delete network;

return error;
}


int process_command();
int check_network();


int step(){
int error;

error = NO_ERROR;
error = check_network();
if(error == NO_ERROR) error = process_command();

return error;
}



int check_network(){
int error;

error = NO_ERROR;

if(*state == WAITINGFORCONNECTION){
if(connect_flag == TRUE){
if(mode == LISTENER){
if(network->wait_read_connection() == NO_ERROR){
char text[200];
*state = CONNECTIONESTABLISHED;
*received_flag = FALSE;
*send_flag = FALSE;
sprintf(text, "Got a connection from %s", network->get_remote_client());
error_log(WARNING, text);
time(&last_time);
}
} else if(mode == TALKER){
if(network->open_write_connection() == NO_ERROR){
*state = CONNECTIONESTABLISHED;
*received_flag = FALSE;
*send_flag = FALSE;
time(&last_time);
}
}
}
} else if(*state == CONNECTIONESTABLISHED){
if(*send_flag == TRUE){
network->write_to_connection(send_buf);
// printf("Sending String [%s]\n", send_buf);
send_buf[0] = 0;
*send_flag = FALSE;
// time(&last_time); // You can keep the connection alive by writing
// but this doesn't guarantee that the remote client is still there
}
if(*received_flag == FALSE){
if(network->read_from_connection(received_temp, 199) != ERROR){
if(strlen(received_temp) > 0){
strcpy(received, received_temp);
*received_flag = TRUE;
time(&last_time);
// printf("Got String [%s]\n", received);
}
}
}
time(&now_time);
if((network->check_connection() == ERROR) || ((mode == LISTENER) && (difftime(now_time, last_time) > timeout))){
if(mode == LISTENER){
network->end_read_connection();
} else if(mode == TALKER){
network->end_write_connection();
}
*state = WAITINGFORCONNECTION;
connect_flag = FALSE;
}
}

return error;
}



int process_command(){
int error;
int i, len;
int port;

error = NO_ERROR;
if(*change_lock == TRUE){
if(*command == INITIALIZE){
if(*state == NOTINITIALIZED){
if(mode == LISTENER){
port = atoi(params);
if(port > 0){
network = new network_io();
network->set_local_host(port);
network->init_read();
//now ready to listen
*state = WAITINGFORCONNECTION;
connect_flag = FALSE;
} else {
error_log(MINOR, "Parameter did not hold a valid port");
*error_flag = ERROR;
}
} else if(mode == TALKER){
len = strlen(params);
for(i = 0; i < len; i++){
if(params[i] == ':'){
params[i] = 0;
port = atoi(&(params[i+1]));
break;
}
}
if((i < len) && (port > 0)){
network = new network_io();
network->set_remote_host(params, port);
network->init_write();
*state = WAITINGFORCONNECTION;
connect_flag = FALSE;
} else {
error_log(MINOR, "Address string was not properly formed");
*error_flag = ERROR;
}
} else {
error_log(MINOR, "ERROR: Mode not defined yet");
*error_flag = ERROR;
}
} else {
error_log(MINOR, "Network talker initialize command in wrong state");
*error_flag = ERROR;
}
} else if(*command == CONNECT){
if(*state == WAITINGFORCONNECTION){
connect_flag = TRUE;
}
} else if(*command == DISCONNECT){
if(*state == CONNECTIONESTABLISHED){
if(mode == TALKER){
network->end_write_connection();
} else if (mode == LISTENER){
network->end_read_connection();
}
*state = WAITINGFORCONNECTION;
connect_flag = FALSE;
} else {
error_log(MINOR, "Cannot disconnect network unless connected");
*error_flag = ERROR;
}
} else if(*command == UNINITIALIZE){
if(*state == WAITINGFORCONNECTION){
if(mode == TALKER){
network->deinit_write();
} else if (mode == LISTENER){
network->deinit_read();
}
delete network;
network = NULL;
*state = NOTINITIALIZED;
} else {
error_log(MINOR, "Cannot uninitialize network unless waitingforconnection");
*error_flag = ERROR;
}
} else if(*command == SET){
if(*operand1 == MODE){
if(*state == NOTINITIALIZED){
mode = *operand2;
} else {
error_log(MINOR, "Can't set network mode after initialization");
*error_flag = ERROR;
}
} else if(*operand1 == PARAM){
if(*state == NOTINITIALIZED){
if(params != NULL) delete params;
params = new char[strlen(operand3)+1];
strcpy(params, operand3);
} else {
error_log(MINOR, "Can't set network parameters, in wrong state");
*error_flag = ERROR;
}
} else if(*operand1 == TIMEOUT){
timeout = *operand2;
} else {
error_log(MINOR, "Network SET type not recognized");
*change_lock = FALSE;
*error_flag = ERROR;
}
} else {
error_log(MINOR, "Network command not recognized");
*error_flag = ERROR;
}
}
*change_lock = FALSE;

return error;
}

To use the network program as a server the basic flow of control is outlined below,

char temp_in[200]; // an input string
char temp_out[200]; // an output string

// set up the network connection
network_io test = new network_io(); // create a new instance of network
test->set_local_host(1000); // set the program to listen on port 1000
point1: test->init_read(); // start waiting for a client to connect
point2: val = test->wait_read_connection(); // check for a connection
if(val == ERROR) goto point2;
val = test->check_connection();
if(val == ERROR){
test->end_read_connection();
goto point1;
}
// now connected, interact with client
point3: val = test->read_from_connection(temp_in, 199); // get an input string
if(val == NO_ERROR){
// do anything needed for the received string
}

// do anything for writing strings here
if(there is a string to send){
test->write_to_connection(temp_out);
}
goto point3;

A makefile for the program follows.

all: network
CC=c++
CFLAGS=
network: network.cpp
$(CC) $(CFLAGS) network.cpp -o network network_io.o
network_io.o: network_io.cpp network_io.h
$(CC) $(CFLAGS) -c network_io.cpp

TOC PREV NEXT