2005年10月31日 星期一

成为软件高手的几个忌讳

评论观点 : 成为软件高手的几个忌讳

2005.10.28 来自:IT人

1) 不会英语:CS源于美国,重量级的文档都是英文的。不会英语,那么你只能忍受拙
劣的翻译和大延迟的文档(翻译出来的文档几乎都是很久以前出版的东西)。

2) 急于求成:什么都没学习就开始编程是最大的机会。写C++程序语法都能错,数据
结构连线性表都不知道,数据库不知道关系模型,TCP编程不知道socket,还是先坐下来学
习几年再说(如果说工作急需,我只能说:早干嘛去了)

3) 过于好问:勤学好问是一种很好的品质,但是如果把勤学丢了,只留下好问,就是
一个恶劣的素质了。事无巨细都去请教别人,一则会让人厌烦,二则由于没有系统学习过程
,也是不可能学习好的。

4) 只会艳羡别人和说别人不该拿那么多钱,而自己却收入微薄:老实说,绝大多数情
况下,收入的高低和你的水平是有正相关关系的。不是否认有关系的存在,但是绝对不会10
个人中9个人有关系而独独你没有。少抱怨一些多学习一些,提升自己才是最重要的。

5) 过于不求甚解和过于求甚解。了解为什么是很重要的,但是要学习的东西很多,如
果什么都弄明白,那么估计头发白了还没有找到所有答案。当然如果什么都不想细致了解,
那么只能去做蓝领了。

6) 过分崇拜他人:我想信很多人都是很厉害的,值得大家崇拜,但是如果过于崇拜,
把他们的话当成圣经就没有必要了。你需要突破他们,而不是崇拜他们。

7) 不想吃苦:IT业高收入和高竞争是联系在一起的。没有付出永远别想进步。


由 beat 发表于 下午05点11分 | 回复 (0)

2005年10月28日 星期五

Graph Coloring Problems: the archives

http://www.imada.sdu.dk/Research/Graphcol/

由 beat 发表于 上午12点51分 | 回复 (0)

2005年10月27日 星期四

诺基亚手机音乐响铃编辑大法

适用机型:
  Nokia公司推出的手机中,能够设置音乐响铃的包括61XX系列(TDMA制式的6120除外)、3210、7110、8210、8810及8850等型号。


设置方法:
  Nokia手机自编音乐响铃的方法主要分三种:

  3210手机可以直接按数字键输入音符;利用电脑配合专用传送线输入歌曲的手机有3210、61XX系列及7110;而利用电脑配合红外线输入的则有61XX系列、7110、8210、8810及8850手机。

  另外,以上提及的所以诺基亚手机型号,都可通过网络商的服务下载铃声,但可能需要收费。


实践:

  通过网络商下载铃声,请向移动通讯网络商查询。其他方法请看下面的说明:

  (一)3210手机按键输入歌曲

  1.准备工作

  进入“功能表”,选择“铃声设置”,选择“铃声编辑器”。

  2.开始编辑

  输入数字后,手机显示屏上就会有一组组的数字和英文字母出现。

  第一个数字代表节拍。4就是1/4拍,8则代表1/8拍,如此类推。按“8”字可加快拍子,按“9”字可减慢拍子。
  第二个英文字母代表音调。1-7分别代表Do-Xe等七个音,由音调的英文字母(即C-B)代表。
  第三个数字代表所在音阶。“1”代表在第一个音阶,“2”则升高八度。按“*”可升一个音阶。共有三个音阶,故在第三个音阶按“*”,则回复到第一个音阶。
  要注意的是:一个音符在输入新的拍子和音阶后,如果不输入新的指令,其后输入音符的拍子和音阶都不会改变。

  --------------------------
  音符 字母 数字键
  Do C 1
  Re D 2
  Me E 3
   Fa F 4
  So G 5
   La A 6
  Xe B 7
  休止符 R 0
  升8度 - *
  降8度 - **
  半音 # #
  加快拍子 - 8
  减慢拍子 - 9

  --------------------------

  3.保存歌曲


  歌曲输完后,按手机的“操作”键,选“节奏”以调节歌曲节奏,数字越大越快。按“操作”键,再按“播放”可试听,按“保存”可保存,按“发送”则可以短讯形式发送给别人。


  (二)利用手机良伴软件配合红外线输入歌曲(适用于61XX系列、8210及8850)

  1.工具


  手机良伴软件(http://www.mobileaction.com.tw)
  红外线输出套装设备(如天扬MA600,价格约人民币300元,一般通讯商场有售)

  2.准备工作


  安装合适的手机良伴软件(分61XX系列版本、8210版本及8850版),但不要安装红外线套装产品的驱动程序。
  将红外线设备连接到电脑的串行接口(Serial Port)。
  准备好midi格式的音乐文件。

  3.开始编辑


  启动手机的红外线功能。如果是8210或8850手机,则改为进入“游戏”中的“贪食蛇”,再选“二人游戏”。启动手机良伴软件,将红外线设备对准手机的红外线输出口,两者即可连接。
  选择手机良伴软件主操作界面的“加值功能”,再选“自定铃声”,选好一个midi文件后,再按“直接装入”就能够把歌曲传送到手机中。

  4.保存歌曲


  手机会显示“收到铃声”。按“操作”键,选“播放”可试听;按“操作”键,选“保存”,再选保存位置(如果有的话)即可保存。退出后在“操作模式”中选择需要的模式,再选“个人化选择”,选择“铃声类型”就能将歌曲当作电话响铃声使用。   (三)利用Logo manager软件配合红外线或传送线输入歌曲(以上各款手机均适用)

  1.工具


  Logo manager软件(www.logomanager.co.uk)
  MIDI To Tone 2.1软件(http://www.hkplanet.com/~feanna/nokia)
  红外线输出设备(适用于61XX系列、7110、8210、8810及8850)
  Nokia手机传送线(适用于61XX系列、7110及3210)


  2.准备工作


  安装好Logo manager软件,并将红外线或传送线连接到个人电脑的串行接口。
  准备好Midi格式的歌曲文件,并用MIDI To Tone 2.1软件转换成Nokring格式。

  3.开始编辑


  启动电脑的红外线功能。在电脑上安装Logo manager软件。运行此软件,在程序主操作界面中选择“Tools”,再选“Options”。先在“Communications”中选择使用传送线或红外线方式。如果是红外线的话,还要在“IR Port Type”中选“Use IrDA Drivers”。再在“Services Provider”选择适合的手机网络商。
  启动手机的红外线功能,或将传送线连接到手机的接口。在手机显示屏上选择“View”,再选“Edit Ringtone”,装入前面已转换成功的Nokring文件,再选“Upload”就可以将歌曲传送到手机中。
  特别需要注意的是,诺基亚3210手机传送线的接口是机背电池右侧上方的六个圆点,而其传送线也经过专门改装,比普通的传送线略贵。

  4.保存歌曲

  此时,手机会显示“收到铃声”。按“操作”键,选“播放”可试听;按“操作”,选“保存”,再选保存位置(如有的话)即可保存歌曲。退出后在“操作模式”中选择需要的模式,再选“个人化选择”,再选“铃声类型”即可将歌曲当作电话响铃声使用了。

由 beat 发表于 下午07点49分 | 回复 (0)

nokia铃声

beyond 你知道我的迷惘
8e1 8d1 16c1 16c1 16c1 16c1 8c1 8d1 4d1 8e1 8d1 16c1 16c1 16c1 16c1 8e1 8f1 2d116e1 8f1 16g1 16g1 16g1 16g1 16g1 16f1 8e1 4g1 16g1 16g1 8a1 8e1 16e1 16d1 16c1 16d1 4e1 16e1 16d1 4c1 8c1 4d1 16e1 16d1 8c1 2c1 Tempo:80

由 beat 发表于 下午07点34分 | 回复 (0)

2005年10月24日 星期一

BSD Sockets

Here is something I picked up on the Net.
This file contains exaples of client and servers using several protocols, might be very usefull.


BSD Sockets
Sockets are a generalized networking capability first introduced in 4.1cBSD and subsequently refined into their current form with 4.2BSD. The sockets feature is available with most current UNIX system releases. (Transport Layer Interface (TLI) is the System V alternative). Sockets allow communication between two different processes on the same or different machines. Internet protocols are used by default for communication between machines; other protocols such as DECnet can be used if they are available.
To a programmer a socket looks and behaves much like a low level file descriptor. This is because commands such as read() and write() work with sockets in the same way they do with files and pipes. The differences between sockets and normal file descriptors occurs in the creation of a socket and through a variety of special operations to control a socket. These operations are different between sockets and normal file descriptors because of the additional complexity in establishing network connections when compared with normal disk access.

For most operations using sockets, the roles of client and server must be assigned. A server is a process which does some function on request from a client. As will be seen in this discussion, the roles are not symmetric and cannot be reversed without some effort.

This description of the use of sockets progresses in three stages:

The use of sockets in a connectionless or datagram mode between client and server processes on the same host. In this situation, the client does not explicitly establish a connection with the server. The client, of course, must know the server's address. The server, in turn, simply waits for a message to show up. The client's address is one of the parameters of the message receive request and is used by the server for response.

The use of sockets in a connected mode between client and server on the same host. In this case, the roles of client and server are further reinforced by the way in which the socket is established and used. This model is often referred to as a connection-oriented client-server model.

The use of sockets in a connected mode between client and server on different hosts. This is the network extension of Stage 2, above.

The connectionless or datagram mode between client and server on different hosts is not explicitly discussed here. Its use can be inferred from the presentations made in Stages 1 and 3.

--------------------------------------------------------------------------------

Socket Creation Using socketpair()
#include <sys/types.h>
#include <sys/socket.h>

int socketpair(int af, int type, int protocol, int sv[2])

socketpair() results in the creation of two connected sockets. sv[] is the array where the file descriptors for the sockets are returned. Each descriptor in sv[] is associated with one end of the communications link. Each descriptor can be used for both input and output. This means that full two-way communication between a parent process and one child process is possible.
Normally, one descriptor is reserved for use by a parent process and the other descriptor is used by a child process. The parent process closes the descriptor used by the child process. Conversely, the child process closes the descriptor used by the parent process. fork() is still required to pass one of the sockets to a child.

af represents the domain or address family to which the socket belongs. type is the type of socket to create.

Domains refer to the area where the communicating processes exist. Commonly used domains include:


AF_UNIX for communication between processes on one system;
AF_INET for communication between processes on the same or different systems using the DARPA standard protocols (IP/UDP/TCP).
Socket type refers to the "style" of communication. The two most commonly used values include:

SOCK_STREAM: A stream of data with no record boundaries. Delivery in a networked environment is guaranteed; if delivery is impossible, the sender receives an error indicator.
SOCK_DGRAM: A stream of records, each of a given size. Delivery in a networked environment is not guaranteed.
A protocol value of 0 is very common. This permits the system to choose the first protocol which is permitted with the pair of values specified for family and type.
Example (borrowed from 4.3BSD IPC Tutorial by Stuart Sechrest)


#define DATA1 "test string 1"
#define DATA2 "test string 2"

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>

main()
{
int sockets[2], child;
char buf[1024];

/* Get the socket pair */
if (socketpair(AF_UNIX, SOCK_STREAM,
0, sockets) < 0) {
printf("error %d on socketpair\n", errno);
exit(1);
}

/* create child process */
if ((child = fork()) == -1) {
printf("fork error %d\n", errno);
exit(1);
}

if (child != 0) { /* this is the parent */
/* close child's end of socket */
close(sockets[0]);

/* read message from child */
if (read(sockets[1], buf, sizeof(buf)) < 0) {
printf("error %d reading socket\n", errno);
exit(1);
}
printf("-->%s\n", buf);

/* write message to child */
if (write(sockets[1], DATA1, sizeof(DATA1)) < 0) {
printf("error %d writing socket\n", errno);
exit(1);
}

/* finished */
close(sockets[1]);

} else { /* the child */

/* close parent's end of socket */
close(sockets[1]);

/* send message to parent */
if (write(sockets[0], DATA2, sizeof(DATA1)) < 0) {
printf("error %d writing socket\n", errno);
exit(1);
}

/* get message from parent */
if (read(sockets[0], buf, sizeof(buf)) < 0) {
printf("error %d reading socket\n", errno);
exit(1);
}
printf("-->%s\n", buf);

/* finished */
close(sockets[0]);
}
}


--------------------------------------------------------------------------------

Socket Creation Using socket()
#include < sys/types.h>
#include < sys/socket.h>

int socket(int af, int type, int protocol)

socket() is very similar to socketpair() except that only one socket is created instead of two. This is most commonly used if the process you wish to communicate with is not a child process. The af, type, and protocol fields are used just as in the socketpair() system call.
On success, a file descriptor to the socket is returned. On failure, -1 is returned and errno describes the problem.

--------------------------------------------------------------------------------

Giving a Socket a Name - bind()
#include < sys/types.h>
#include < sys/socket.h>

int bind(int s, struct sockaddr *name, int namelen)

Recall that, using socketpair(), sockets could only be shared between parent and child processes or children of the same parent. With a name attached to the socket, any process on the system can describe (and use) it.
In a call to bind(), s is the file descriptor for the socket, obtained from the call to socket(). name is a pointer to a structure of type sockaddr. If the address family is AF_UNIX (as specified when the socket is created), the structure is defined as follows:


struct sockaddr {
u_short sa_family;
char sa_data[14];
};

name.sa_family should be AF_UNIX. name.sa_data should contain up to 14 bytes of a file name which will be assigned to the socket. namelen gives the actual length of name, that is, the length of the initialized contents of the data structure.
A value of 0 is return on success. On failure, -1 is returned with errno describing the error.

Example:


struct sockaddr name;
int s;
name.sa_family = AF_UNIX;
strcpy(name.sa_data, "/tmp/sock");
if((s = socket(AF_UNIX, SOCK_STREAM, 0) < 0)
{
printf("socket create failure %d\n", errno);
exit(0);
}
if (bind(s, &name, strlen(name.sa_data) +
sizeof(name.sa_family)) < 0)
printf("bind failure %d\n", errno);


--------------------------------------------------------------------------------

Specifying a Remote Socket - connect()
#include < sys/types.h>
#include < sys/socket.h>

int connect(int s, struct sockaddr *name, int namelen)

The bind() call only allows specification of a local address. To specify the remote side of an address connection the connect() call is used. In the call to connect, s is the file descriptor for the socket. name is a pointer to a structure of type sockaddr:

struct sockaddr {
u_short sa_family;
char sa_data[14];
};

As with the bind() system call, name.sa_family should be AF_UNIX. name.sa_data should contain up to 14 bytes of a file name which will be assigned to the socket. namelen gives the actual length of name. A return value of 0 indicates success, while a value of -1 indicates failure with errno describing the error.
A sample code fragment:

struct sockaddr name;

name.sa_family = AF_UNIX;
strcpy(name.sa_data, "/tmp/sock");

if (connect(s, &name, strlen(name.sa_data) +
sizeof(name.sa_family)) < 0) {
printf("connect failure %d\n", errno);
}


--------------------------------------------------------------------------------

Sending to a Named Socket - sendto()
int sendto(int s, char *msg, int len, int flags,
struct sockaddr *to, int tolen)

This function allows a message msg of length len to be sent on a socket with descriptor s to the socket named by to and tolen, where tolen is the actual length of to. flags will always be zero for our purposes. The number of characters sent is the return value of the function. On error, -1 is returned and errno describes the error.
An example:


struct sockaddr to_name;

to_name.sa_family = AF_UNIX;
strcpy(to_name.sa_data, "/tmp/sock");

if (sendto(s, buf, sizeof(buf), 0, &to_name,
strlen(to_name.sa_data) +
sizeof(to_name.sa_family)) < 0) {
printf("send failure\n");
exit(1);
}


--------------------------------------------------------------------------------

Receiving on a Named Socket - recvfrom()
#include < sys/types.h>
#include < sys/socket.h>

int recvfrom(int s, char *msg, int len, int flags,
struct sockaddr *from, int *fromlen)

This function allows a message msg of maximum length len to be read from a socket with descriptor s from the socket named by from and fromlen, where fromlen is the actual length of from. The number of characters actually read from the socket is the return value of the function. On error, -1 is returned and errno describes the error. flags may be 0, or may specify MSG_PEEK to examine a message without actually receiving it from the queue.
If no message is available to be read, the process will suspend waiting for one unless the socket is set to nonblocking mode (via an ioctl call).

The system I/O call read() can also be used to read data from a socket.

--------------------------------------------------------------------------------

Disposing of a Socket
#include < stdio.h>

void close(int s).

The I/O call close() will close the socket descriptor s just as it closes any open file descriptor.
Example - sendto() and recvfrom()


/* receiver */
#include < sys/types.h>
#include < sys/socket.h>

struct sockaddr myname;
struct sockaddr from_name;
char buf[80];

main()
{
int sock;
int fromlen, cnt;

sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock < 0) {
printf("socket failure %d\n", errno);
exit(1);
}

myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/tsck");

if (bind(sock, &myname, strlen(myname.sa_data) +
sizeof(name.sa_family)) < 0) {
printf("bind failure %d\n", errno);
exit(1);
}

cnt = recvfrom(sock, buf, sizeof(buf),
0, &from_name, &fromlen);
if (cnt < 0) {
printf("recvfrom failure %d\n", errno);
exit(1);
}

buf[cnt] = '\0'; /* assure null byte */
from_name.sa_data[fromlen] = '\0';

printf("'%s' received from %s\n",
buf, from_name.sa_data);
}

/* sender */
#include < sys/types.h>
#include < sys/socket.h>

char buf[80];
struct sockaddr to_name;

main()
{
int sock;

sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sock < 0) {
printf("socket failure %d\n", errno);
exit(1);
}

to_name.sa_family = AF_UNIX;
strcpy(to_name.sa_data, "/tmp/tsck");

strcpy(buf, "test data line");

cnt = sendto(sock, buf, strlen(buf), 0, &to_name,
strlen(to_name.sa_data) + sizeof(to_name.sa_family));
if (cnt < 0) {
printf("sendto failure %d\n", errno);
exit(1);
}
}


--------------------------------------------------------------------------------

A Refinement: Client-Server Connections
Sockets can be used to write client-server applications using a connection-oriented client-server technique. Some characteristics of this technique include:

The server can handle multiple client requests for connection and service.
The server responds to any one client's request independently of all other clients.
A client knows how to establish a connection with the server.
The client-server connection, when established, remains in existence until either the client or the server explicitly breaks it, much like a trouble-free telephone call. The socket used for this connection is called a connection-oriented socket.
The socket type is specified as SOCK_STREAM. As a result, the process receiving a message processes that message by the following rules:


The data transmitted has no boundaries.
All bytes in a received message must be read before the next message can be processed.
Bytes in a received message can be read in a loop program control structure since no data bytes are discarded.
The server will usually fork() a child process upon establishment of a client connection.
This child server process is designed to communicate with exactly one client process.
The child server process performs the requested service for its connected client.
The child server process terminates when the service request has been completed.
Functions listen() and accept() enable the server to listen for service requests. read() and write() may be used by client and server to send/receive messages; send() and recv() may also be used.
--------------------------------------------------------------------------------

Make a Socket a Listen-only Connection Endpoint - listen()
#include < sys/types.h>
#include < sys/socket.h>

int listen(int s, int backlog)

listen establishes the socket as a passive endpoint of a connection. It does not suspend process execution.
No messages can be sent through this socket. Incoming messages can be received.

s is the file descriptor associated with the socket created using the socket() system call. backlog is the size of the queue of waiting requests while the server is busy with a service request. The current system-imposed maximum value is 5.

0 is returned on success, -1 on error with errno indicating the problem.


Example:

#include < sys/types.h>
#include < sys/socket.h>

int sockfd; /* socket file descriptor */

if(listen(sockfd, 5) < 0)
printf ("listen error %d\n", errno);


--------------------------------------------------------------------------------

Connection Establishment by Server - accept()
#include < sys/types.h>
#include < sys/socket.h>

int accept(int sockfd, struct sockaddr *name, int *namelen)

The accept() call establishes a client-server connection on the server side. (The client requests the connection using the connect() system call.) The server must have created the socket using socket(), given the socket a name using bind(), and established a listen queue using listen().
sockfd is the socket file descriptor returned from the socket() system call. name is a pointer to a structure of type sockaddr as described above


struct sockaddr {
u_short sa_family;
char sa_data[14];
};

Upon successful return from accept(), this structure will contain the protocol address of the client's socket.
The data area pointed to by namelen should be initialized to the actual length of name. Upon successful return from accept, the data area pointed to by namelen will contain the actual length of the protocol address of the client's socket.

If successful, accept() creates a new socket of the same family, type, and protocol as sockfd. The file descriptor for this new socket is the return value of accept(). This new socket is used for all communications with the client.

If there is no client connection request waiting, accept() will block until a client request is queued.

accept() will fail mainly if sockfd is not a file descriptor for a socket or if the socket type is not SOCK_STREAM. In this case, accept() returns the value -1 and errno describes the problem.

--------------------------------------------------------------------------------

Data Transfer over Connected Sockets - send() and recv()
Two additional data transfer library calls, namely send() and recv(), are available if the sockets are connected. They correspond very closely to the read() and write() functions used for I/O on ordinary file descriptors.

#include < sys/types.h>
#include < sys/socket.h>

int send(int sd, char *buf, int len, int flags)

int recv(int sd, char * buf, int len, int flags)

In both cases, sd is the socket descriptor.
For send(), buf points to a buffer containing the data to be sent, len is the length of the data and flags will usually be 0. The return value is the number of bytes sent if successful. If not successful, -1 is returned and errno describes the error.

For recv(), buf points to a data area into which the received data is copied, len is the size of this data area in bytes, and flags is usually either 0 or set to MSG_PEEK if the received data is to be retained in the system after it is received. The return value is the number of bytes received if successful. If not successful, -1 is returned and errno describes the error.

--------------------------------------------------------------------------------

A Connection-Oriented Example - listen(), accept()
/* Generic program structure for establishing
connection-oriented client-server environment. */

/* server program */

#include < stdio.h>
#include < errno.h>
#include < signal.h>
#include < sys/types.h>
#include < sys/socket.h>

struct sockaddr myname;
char buf[80];

main()
{
int sock, new_sd, adrlen, cnt;

sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("server socket failure %d\n", errno);
perror("server: ");
exit(1);
}

myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) +
sizeof(myname.sa_family);

unlink("/tmp/billb"); /* defensive programming */
if (bind(sock, &myname, adrlen) < 0) {
printf("server bind failure %d\n", errno);
perror("server: ");
exit(1);
}

if (listen(sock, 5) < 0 {
printf("server listen failure %d\n", errno);
perror("server: ");
exit(1);
}

/* Ignore child process termination. */

signal (SIGCHLD, SIG_IGN);

/* Place the server in an infinite loop, waiting
on connection requests to come from clients.
In practice, there would need to be a clean
way to terminate this process, but for now it
will simply stay resident until terminated by
the starting terminal or the super-user. */

while (1) {
if (new_sd = accept(sock, &myname, &adrlen)) < 0 {
printf("server accept failure %d\n", errno);
perror("server: ");
exit(1);
}

/* Create child server process. Parent does no
further processing -- it loops back to wait
for another connection request. */

printf("Socket address in server %d is %x, %s\n",
getpid(), myname.sa_data, myname.sa_data);

if (fork() == 0) { /* child process */
close (sock); /* child does not need it */
/* . . . . . */

cnt = read(new_sd, buf, strlen(buf));
printf ("Server with pid %d got message %s\n",
getpid(), buf);
strcpy (buf, "Message to client");
cnt = write(new_sd, buf, strlen(buf));
printf("Socket address in server %d is %x, %s\n",
getpid(), myname.sa_data, myname.sa_data);

/* . . . . . */
close (new_sd); /* close prior to exiting */
exit(0);
} /* closing bracket for if (fork() ... ) */

} /* closing bracket for while (1) ... ) */

} /* closing bracket for main procedure */

/* client program */

#include < stdio.h>
#include < errno.h>
#include < sys/types.h>
#include < sys/socket.h>

char buf[80];
struct sockaddr myname;

main()
{
int sock, adrlen, cnt;

sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("client socket failure %d\n", errno);
perror("client: ");
exit(1);
}

myname.sa_family = AF_UNIX;
strcpy(myname.sa_data, "/tmp/billb");
adrlen = strlen(myname.sa_data) +
sizeof(myname.sa_family);

if (connect( sock, &myname, adrlen) < 0) {
printf("client connect failure %d\n", errno);
perror("client: ");
exit(1);
}
/* . . . . . */

strcpy(buf, "Message sent to server");
cnt = write(sock, buf, strlen(buf));
cnt = read(sock, buf, strlen(buf));
printf("Client with pid %d got message %s\n",
getpid(), buf);
printf("Socket address in server %d is %x, %s\n",
getpid(), myname.sa_data, myname.sa_data);

/* . . . . . */
exit(0);
}


--------------------------------------------------------------------------------

Connecting Across a Network
Sending data across a network is done in much the same way as sending data on a single machine. Establishing a connection is more difficult as a simple file name is not common among different machines. This is why networking domains other than AF_UNIX exist.
The following pages describe several of the routines available to establish a network connection. All these functions are for use with the AF_INET domain. The concept of network addressing is discussed first.

--------------------------------------------------------------------------------

Network Addresses - The IP Address
The IP host address, or more commonly just IP address, is used to identify hosts connected to the Internet. IP stands for Internet Protocol and refers to the Internet Layer of the overall network architecture of the Internet. An IP address is a 32-bit quantity interpreted as 4 8-bit numbers or octets. Each IP address uniquely identifies the participating user network, the host on the network, and the class of the user network.
An IP address is usually written in a dotted-decimal notation of the form N1.N2.N3.N4, where each Ni is a decimal number between 0 and 255 decimal (00 through ff hexadecimal). Addresses are controlled and assigned by the Internet Network Information Center at SRI International. There are currently 5 defined classes of networks, called A, B, C, D and E; classes A, B and C are available to users. Each interface on a host system connected to the Internet must have its own IP address.

A brief synopsis of IP address classes A, B, and C is contained in the following table.


Class/Attribute ABC Address Format N.H.H.HN1.N2.H.HN1.N2.N3.HFirst Octet0 < N < 127128 <= N1 <192192<= N1 < 224Network IDNN1.N2N1.N2.N3Host IDH.H.HH.HHAvailabilityVery difficultAlmost exhaustedAmple supplyExample10.133.51.224128.247.116.3192.58.103.7

SubnetsAs the number of hosts on a given network grew large and more geographically separated, network management considerations and physical layer limitations such as maximum cable length gave impetus to research into possible changes in network installations without massive disruptions. Also, the use of heterogeneous physical layer networks (e.g., Ethernet and Token Ring) with the same IP network address was increasing.
The concept of subnet was introduced to help solve these problems. The benefits for Class A and Class B networks especially are worth the subnet planning and implementation effort.

The basic idea in subnetworking (a common word also used is subnetting) is to partition the host identifier portion of the IP address into two parts:


A subnet address within the network address itself; and
A host address on the subnet.
For example, a common Class B address format is N1.N2.S.H, where N1.N2 identifies the Class B network, the 8-bit S field identifies the subnet, and the 8-bit H field identifies the host on the subnet.


--------------------------------------------------------------------------------

Network Host Names
Using IP addresses to access hosts on a network is fine for the IP software. Most people are more comfortable with names, and procedures for both proper name construction and translation of these names into IP addresses has been in existence for some time. The most commonly used is the Domain Name System (DNS), occasionally but inaccurately referred to as the Domain Name Service. Naming in DNS is done hierarchically, that is, in a tree-structure format, much like the UNIX file system naming. The top two levels are controlled by the Internet Network Information Center (NIC) at SRI International.
At the top of the domain are two-letter country designators and three-letter (usually) general category designators within the USA. Some examples are:


fr -- France
gov -- government
nz -- New Zealand
com -- commercial business
us -- USA
edu -- educational institution
uk -- United Kingdom
mil -- military
The next level usually identifies the institution. For example:

ibm -- IBM Corporation
utdallas -- UT-D
ti -- Texas Instruments (TI)
nasa -- NASA
The combination of these should be enough to specify the name, type and location of the organizational entity. For example:

ukuug.uk -- UNIX Users Group in the United Kingdom
utdallas.edu -- University of Texas at Dallas in the USA
ti.com -- Texas Instruments in the USA

Further hierarchies may be established within these organizations and are controlled locally. Some examples of host names are:

csservr2.utdallas.edu -- host csservr2 at UT-D
pac1.pac.sc.ti.com -- host pac1 within domain pac within domain sc at TI
sunk.ssc.gov -- host sunk at the Superconducting SuperCollider Laboratory

DNS and other software help in maintenance of these naming conventions and in the translation of host names to IP addresses and vice versa.


--------------------------------------------------------------------------------

The /etc/hosts File
The correspondence between host names and IP addresses is maintained in a file called hosts in the (top-level) directory /etc. On most systems, any user can read this file. (A word of caution: on many systems, printing this file may be injurious to local paper supply!!)
Entries in this file look like the following:


127.0.0.1 localhost
192.217.44.208 snoopy beagle hound metlife
153.110.34.18 bugs wabbit wascal
153.110.34.19 elmer
153.110.34.20 sam

Note that more than one name may be associated with a given IP address. This file is used when converting from IP address to host name and vice versa.


--------------------------------------------------------------------------------

Selecting a Service Port
The protocol specifications of the protocols used in the AF_INET domain require specification of a port. The port number is used to determine which process on the remote machine to talk to.
Certain network services have been assigned Well Known Ports. The port assignments to network services can be found in the file /etc/services. Selection of a Well Known Port involves searching this file and is done with the following functions:


#include < netdb.h>

struct servent *getservbyname(char *name, char *proto)

struct servent *getservbyport(int port, char *proto)

The two options for proto in each call are tcp for stream oriented communications, and udp for datagram oriented communications. port is the (known) port number when the service name is requested, while name is the character string containing the service name when the port number is requested.
The return value for each function is a pointer to a structure with the following form:

struct servent {
char *s_name; /* official name of service */
char **s_aliases; /* alias service name list */
long s_port; /* port service resides at */
char *s_proto; /* protocol to use */
};

If a program does not need to communicate with a Well Known Port it is possible to choose an unused port for use by a program. Illustration of this technique is contained in the sample programs below.


--------------------------------------------------------------------------------

Putting a Host Program Address Together
Once a host address and port number are known then the complete process address must be put together in a form that may be used by the system calls already covered. The structures set up to allow this follow:

#include < netinet/in.h>

/*
* Internet address (a structure for historical reasons)
*/
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr
/* can be used for most tcp & ip code */
};


/*
* Socket address, internet style.
*/
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};

Filling in the fields for sockaddr_in will produce an Internet version of a socket address.


--------------------------------------------------------------------------------

Finding a Machine Address
Finding an address that can be used to connect to a remote machine is done with either of the following commands:

#include < netdb.h>

struct hostent *gethostbyname(char *name)

struct hostent *gethostbyaddr(char *addr, int len, int type)

name contains the host name for which the IP address is needed. addr points to a structure of type in_addr and len is the size in bytes of this structure. In this discussion type is always AF_INET since the discussion is limited to use of IP addresses on the Internet.
Both calls return a pointer to a host entry structure. This structure has the following form:


struct hostent {
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* address type */
int h_length; /* length of address */
char **h_addr_list;
/* list of addresses from name server */
#define h_addr h_addr_list[0]
/* address for backward compatibility */
};


--------------------------------------------------------------------------------

Network Byte Order for Numbers
Not all machine architectures use the same internal representations for numbers. For instance, in host systems based on Intel microprocessors and the DEC VAX architecture bytes are stored in increasing memory locations in reverse or "little-endian" order. All other systems store bytes in increasing memory locations in "normal" or "big-endian" order.
Left as is, communications between, e.g., IBM-compatible PCs and Sun Microsystems workstations would be difficult at best. To overcome this all data sent over a network is converted to Network Byte Order which is, in the context of the above discussion, "big-endian" order.

Routines for converting data between a host's internal representation and Network Byte Order are:


#include < sys/types.h>
#include < netinet/in.h>

u_long htonl(u_long hostlong);

u_short htons(u_short hostshort);

u_long ntohl(u_long netlong);

u_short ntohs(u_short netshort);

These functions are macros and result in the insertion of conversion source code into the calling program. On little-endian machines the code will change the values around to network byte order. On big-endian machines no code is inserted since none is needed; the functions are defined as null.


--------------------------------------------------------------------------------

Network Address Conversion Routines
An Internet address is usually written and specified in the dotted-decimal notation described above. Internally it becomes part of a structure of type in_addr. To convert between these two representations two functions are available.

#include < sys/types.h>
#include < sys/socket.h>
#include < netinet/in.h> /* in_addr structure */

unsigned long inet_addr(char *ptr)

char *inet_ntoa(struct in_addr inaddr)

inet_addr() converts a character string in dotted-decimal notation to a 32-bit Internet address. The return value is not consistent, unfortunately. The correct return should be a pointer to a structure of type in_addr but many systems, following an older convention, return only the internal representation of the dotted-decimal notation. The man pages will clarify the situation for the host system on which the function is used.
inet_ntoa() expects a structure of type in_addr as a parameter (note that the structure itself is passed, not a pointer) and returns a pointer to a character string containing the dotted-decimal representation of the Internet address.

--------------------------------------------------------------------------------

Internet Connection-Oriented Client-Server Example
The next two sections contain sample programs for server and client when connection-oriented communication across the Internet (using TCP) is requested. The server and client programs are named vcserver and vcclient, respectively. As built, the programs have some restrictions:

vcserver should be started first as a background job.
The port number reported by vcserver should be copied for use by the client.
The process id of vcserver should also be copied, for use in terminating vcserver when the test is finished.
vcclient is then started.
If vcclient is started on the same host as vcserver is running, the command line to start vcclient is

vcclient localhost server-port-number

If vcclient is started on a host different from the host on which vcserver is running, the command line to start vcclient is

vcclient server-host-name server-port-number

vcserver will remain resident until the user terminates it. The cleanest way to do this is

kill -15 pid

where pid is the process id of vcserver.


--------------------------------------------------------------------------------

Server Source Listing - vcserver.c
/* vcserver.c -- TCP network (virtual circuit) server */

#include < stdio.h>
#include < errno.h>
#include < sys/types.h>
#include < sys/socket.h>
#include < netinet/in.h> /* sockaddr_in structure */

/* This entry allows the program to look up the name
of the host and any alias names associated with it. */

#include < netdb.h> /* /etc/hosts table entries */

main (int argc, char *argv[])

{
int rc, /* system call return code */
new_sd, sock, /* server/listen socket descriptors */
adrlen, /* sockaddr length */
cnt; /* number of bytes I/O */

struct sockaddr_in myname; /* Internet socket name */
struct sockaddr_in *nptr; /* ptr to get port number */
struct sockaddr addr; /* generic socket name */

char buf[80]; /* I/O buffer, kind of small */

/* For lookup in /etc/hosts file. */

struct hostent *hp, *gethostbyaddr();

/* Identify the server process. */

printf("\nThis is the network server with pid %d\n",
getpid() );

/* As in UNIX domain sockets, create a "listen" socket */

if (( sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("network server socket failure %d\n", errno);
perror("network server");
exit(1);
/* Initialize the fields in the Internet socket name
structure. */

myname.sin_family = AF_INET; /* Internet address */
myname.sin_port = 0; /* System will assign port # */
myname.sin_addr.s_addr = INADDR_ANY; /* "Wildcard" */

/* Bind the Internet address to the Internet socket */

if (bind(sock, &myname, sizeof(myname) ) < 0 ) {
close(sock); /* defensive programming */
printf("network server bind failure %d\n", errno);
perror("network server");
exit(2);
}

/* Get the port number assigned to the Internet socket.
getsockname() obtains the port number associated
with the bound socket and returns it as part of the
information in the sockaddr addr structure. Note
that, since the port number is not passed directly
by this program to any client, the only way to
"advertise" it is to print it, that is, send it to
the user's stdout. Other than this printout, this
code is not intrinsic to the connectivity process.
*/

adrlen = sizeof(addr); /* need int for return value */
if ( ( rc = getsockname( sock, &addr, &adrlen ) ) < 0 )
{
printf("setwork server getsockname failure %d\n",
errno);
perror("network server");
close (sock);
exit(3);
}

/* DEBUG CODE: the generic address "addr" is used to
return the socket value obtained from the
getsockname() call. Print this information. In the
generic structure definition, all but the address
family is defined as a char string. After this
call, the generic address structure addr is used to
hold information about the client process. */

printf("\nAfter getsockname():");
printf(" server listen socket data\n");
printf("\taddr.sa_family field value is: %d\n",
addr.sa_family);
printf("\taddr.sa_data string is %d bytes long;\n",
sizeof ( addr.sa_data ) );
printf("\taddr.sa_data string is:");
for ( cnt = 0: cnt < sizeof (addr.sa_data); cnt++)
printf(" %x", addr.sa_data[cnt]);
printf("\n");

/* Now "advertise" the port number assigned to the
socket. In this example, this port number must be
used as the second command line parameter when
starting up the client process. */

/* Note the use of the pointer nptr, with a different
mapping of the allocated memory, to point to the
generic address structure. */

nptr = (struct sockaddr_in *) &addr; /* port # */
printf("\n\tnetwork server: server has port number: %d\n",
ntohs ( nptr -> sin_port ) );

/* Mark the socket as a "listen-only" or passive socket */

if ( listen ( sock, 5 ) < 0 ) {
printf("network server bind failure %d\n", errno);
perror("network server");
close (sock);
exit(4);
}

/* Debug output: information contained in myname structure
(the Internet socket). */

printf("Server has set up client socket with values:\n");
printf("\tInternet address is %lx\n", myname.sin_addr.s_addr);
printf("\tPort number used is %d\n", myname.sin_port);
printf("\tInternet family ID is %d\n", myname.sin_family);
printf("\tValues are filled in after connection request ");
printf("is accepted.");

/* Set up "infinite loop" to listen for clients. Since the
structure "myname" is bound to the listen socket, the
socket structure name and socket length parameter
values are omitted from the accept call. The bound values
are used. */

while (1) {
if ( ( new_sd = accept ( sock, 0, 0 ) ) < 0 ) {
printf("network server accept failure %d\n", errno);
perror("network server");
close (sock);
exit(5);
}

/* Fork child process to handle client service request */

if ( ( fork() ) == 0 ) { /* Child process */

int pid;

pid = getpid(); /* PID of child process */
close (sock); /* Do not need listen socket in child. */

/* Find out who the client is. Note the use of the
generic address structure addr to hold information
about the (connected) client. */

if ((rc = getpeername( new_sd, &addr, &adrlen )) < 0) {
printf("network server %d getpeername failure %d\n",
pid, errno);
perror("network server");
close(new_sd);
exit(6);
}
/* Just for grins, "announce" the client. Note that,
since pointer nptr is of type struct sockaddr_in,
the field names as defined in the structure template
sockaddr_in can be used to access values in the addr
generic structure. */

printf("\n\tnetwork server %d:", pid);
printf(" client socket from host %s\n",
inet_ntoa ( nptr -> sin_addr ) );
printf("\t has port number %d\n",nptr -> sin_port);

/* Now find all names associated with the client; this
is the reason for the /etc/hosts file lookup
declarations. */

if (( hp = gethostbyaddr (&nptr -> sin_addr,4,AF_INET))
!= NULL ) {
printf ("\tfrom hostname: %s\n\twith aliases: ",
hp -> h_name );
while ( *hp -> h_aliases )
printf ("\n\t\t\t%s", *hp -> h_aliases++ );
printf("\n\n");
}
else {
printf("network server %d ", pid);
printf("gethostbyaddr failure %d\n", h_errno);
perror("network server");
}

/* Exchange data with client. Clear buffer first. */

do {

/* Take your pick, depending on system pedigree.
The System V function has not been tested as of
this edition. */

bzero( buf, sizeof(buf)); /* zero buf, BSD call. */
/* memset (buf,0,sizeof(buf)); /* zero buf, S5. */

/* Read message from remote client; if message length
= 0, quit. */

if (( cnt = read (new_sd, buf, sizeof(buf))) < 0 ) {
printf("network server %d ", pid);
printf("socket read failure &d\n", errno);
perror("network server");
close(new_sd);
exit(7);
}
else
if (cnt == 0) {
printf("network server received message");
printf(" of length %d\n", cnt);
printf("network server closing");
printf(" client connection...\n");
close (new_sd);
continue; /* break out of loop */
}
else {

/* Print out message received from client. Send
a message back. */

printf("network server %d received message",pid);
printf(" of length %d\n", cnt);
printf("network server %d received", pid));
printf(" the message %s\n", buf);
bzero (buf, sizeof(buf)); /* zero buf, BSD. */
/* memset(buf,0,sizeof(buf)); /* zero buf, S5. */
strcpy(buf, "Message from server to client");
write (new_sd, buf, sizeof(buf));
} /* end of message-print else */

} /* end of do loop statement */

while (cnt != 0); /* do loop condition */
exit(0); /* Exit child process */

} /* End of if-child-process true condition */

else /* Not child process; must be parent process */

close (new_sd); /* Parent doesn't need work socket. */

} /* end of while (1) */

} /* end of main procedure */

Client Source Listing - vcclient.c

/* vcclient.c -- TCP network (virtual circuit) client */

#include < stdio.h>
#include < errno.h>
#include < sys/types.h>
#include < sys/socket.h>
#include < netinet/in.h> /* sockaddr_in structure */

/* This entry allows the program to look up the name
of the host and any alias names associated with it. */

#include < netdb.h> /* /etc/hosts table entries */

main (argc, argv)
int argc;
char *argv[];

/* Expected command line parameters:

argv[0] -- name of executable
argv[1] -- the host name to which connection is desired
argv[2] -- the port number to be used by the client: the
value is the port number assigned to the
server by the server's host system.

This is not elegant, but is very useful for debugging the
connectivity code. For example, if the host name ( argv[1] )
were speficied as "localhost" both client and server
could run on the same system but the network connectivity
code would still be fully exercised. */

{
int sock, /* socket descriptor */
val, /* scratch variable */
cnt; /* number of bytes I/O */

struct sockaddr_in myname; /* Internet socket name (addr) */
struct sockaddr_in *nptr; /* pointer to get port number */

char buf[80]; /* I/O buffer, kind of small */

/* For lookup in /etc/hosts file. */

struct hostent *hp, *gethostbyaddr();

/* Check that the user supplied all parameters on the
command line. If so, convert argv[2] to integer; copy it
into the sin_port field of the myname structure. Use
the htons function to insure that the value is stored
in network byte order. */

if ( argc < 3 ) {
printf("network client failure: required parameters");
printf(" missing from the command line\n");
printf("network client: usage");
printf("[executable-name] [host name] [port number]\n");
exit(1);
}

/* As in UNIX domain, create a client socket to request
service */

if (( sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("network client socket failure %d\n", errno);
perror("network client");
exit(2);
}

/* Convert user-supplied port number to integer. There is
no consistency check possible in this set-up. */

myname.sin_port = htons( atoi(argv[2]) ); /* Server port # */

myname.sin_family = AF_INET; /* Internet domain */

/* For display purposes only, print out the host name and
the converted port number. */

printf("network client %s will try to connect to host %s\n",
argv[0], argv[1]);
printf("network client %s will use port number %d\n",
argv[0], ntohs ( myname.sin_port ) );

/* Obtain server host information. */

hp = gethostbyname ( argv[1] );

/* This is mainly debug code; if it becomes necessary to
insert it (or if it just feels more comfortable to
have it in place!!!) don't remove it when all is working
well. Rather, leave it in place as a comment. */

if ( hp == NULL ) {
printf("network client gethostbyname failure %d\n",
errno);
perror("network client");
close ( sock );
exit(3);
}
else {
printf("\nServer information obtained via");
printf(" gethostbyname:\n");
printf("\tThe official host name is %s\n", hp -> h_name);
printf("\tThe address type is %d\n", hp -> h_addrtype);
printf("\tThe length of the address is %d bytes\n",
hp -> h_length);
printf("\tThe first host address is %lx\n",
ntohl ( * (int * ) hp -> h_addr_list[0] ) );
printf("\tAlias names for the host are:\n");
while ( *hp -> h_aliases )
printf( "\t\t%s\n", *hp -> h_aliases++ );
}

/* Use either memcpy or bcopy as appropriate
(System V vs BSD). */

bcopy ( hp -> h_addr_list[0], &myname.sin_addr.s_addr,
hp -> h_length );
/* memcpy ( &myname.sin_addr.s_addr, hp -> h_addr_list[0],
hp -> h_length ); */

/* More debug code: Verify the contents of structure myname
prior to trying to connect to the (remote) server. */

printf("\nInformation provided in client's");
printf(" connect request\n");
printf("\tRemote host address is %lx\n",
ntohl ( myname.sin_addr.s_addr ) );
printf("\tPort number supplied is %d\n",
ntohs ( myname.sin_port ) );
printf("\tInternet family ID is %d\n", myname.sin_family);
printf("\tsin_zero character string is: %s\n",
myname.sin_zero);

/* Establish socket connection with (remote) server. */

if ( ( connect ( sock, &myname, sizeof(myname) ) ) < 0 ) {
printf("network client %s connect failure %d\n",
argv[0], errno);
perror("network client");
close (sock);
exit(4);
}

/* Exchange data with client. Clear buffer bytes first. */

/* Take your pick, depending on your system's pedigree. The
System V function has not been tested. */

bzero ( buf, sizeof( buf) ); /* zero buffer, BSD. */
/* memset ( buf, 0, sizeof( buf) ); /* zero buffer S5. */

strcpy ( buf, "Message from client to server" );
write ( sock, buf, sizeof(buf) );

/* Now read message sent back by server. */

if ( ( cnt = read (sock, buf, sizeof(buf) ) ) < 0 ) {
printf("network client socket read failure &d\n", errno);
perror("network client");
close(sock);
exit(5);
}
else
printf("network client received the message %s\n", buf);

/* Now send a message with 0 bytes. */

bzero ( buf, sizeof( buf) ); /* zero buffer, BSD. */
/* memset ( buf, 0, sizeof( buf) ); /* zero buffer S5. */
write ( sock, buf, 0 );
close (sock);
exit(0);

} /* end of main procedure */

由 beat 发表于 下午03点14分 | 回复 (0)

2005年10月23日 星期日

SuSE Linux安装chm文件阅读软件

Linux默认安装不支持阅读chm格式的文件,但是有许多文档以chm格式发布,是个很头疼的问题。
经过google搜索发现可以安装几个类似的软件,比如chmsee,chmviewer,xchm等等。网上介绍认为xchm是个不错的选择。以下是我安装的过程:
从sourceforge上下载xchm1.2源代码,下载地址:
http://sourceforge.net/project/showfiles.php?group_id=87007
安装xchm需要两个包支持,一个是 wxGTK,另一个是 chmlib。
下载wxGTK的地址是:http://www.wxwidgets.org/
下载chmlib的地址是:http://66.93.236.84/%7Ejedwin/projects/chmlib/
分别是:wxWidgets-2.6.2.tar.gz和chmlib-0.36.tgz。
安装wxGTK的过程没有问题,只需要tar configure make make install就可以了
安装chmlib-0.36.tgz时配置编译均没有问题,但是make install的时候不能把库文件拷到/usr/lib或/usr/local/lib下面。需要手动把src/.libs生成的库文件拷到相应目录下面。
然后ldconfig
然后解压 xchm-1.2.tar.gz并按正常过程安装。
之后可以查看chm文件了。不过不幸的是xchm只能看英文文档,中文文档无法正确显示。

然后我选择继续安装chmsee-0.9.5,源码下载地址:http://linuxfire.dhis.org/~zhong/
chmsee需要安装libgtkhtml,我已事先安装了 gtkhtml3.8_3.8.1。
tar -xvf chmsee-0.9.5.tar.bz2
./configure
配置过程中报找不到gtkhtml-3.1
解决方案:
ln -s /usr/local/lib/pkgconfig/libgtkhtml-3.8.pc /usr/local/lib/pkgconfig/libgtkhtml-3.1.pc
然后./configure
make
make install
一切ok。可以正常阅读chm文件了,只需要在chmsee启动时选择编码就可以了。

由 beat 发表于 下午09点06分 | 回复 (1)

2005年10月21日 星期五

Acrobat Reader7 中文支持

SuSE Linux 10.0 默认安装了Adobe Reader 7.0.1-4,但是不能支持中文pdf文档阅读。目前Adobe官方网站并没有给出Adobe Reader 7.x for Linux的亚洲语言字体包。

我的解决方案是:从Adobe官方网站下载Adobe Reader 5.x for Unix的亚洲语言字体包,chsfont.tar.gz,
下载地址:ftp://ftp.adobe.com/pub/adobe/acrobatreader/unix/5.x/chsfont.tar.gz
tar -zxvf chsfont.tar.gz
cd CHSKIT/
tar -xvf LANGCHS.TAR
tar -xvf LANGCOM.TAR
把所有解压后的所有文件拷贝到 /usr/X11R6/lib/Acrobat7/Resource/CMap/即可。

由 beat 发表于 下午08点35分 | 回复 (1)

安装prozilla,多线程下载加速软件

源码下载地址http://prozilla.genesys.ro/downloads/prozilla/tarballs/,我下载的版本是prozilla-2.0.0-r1.tar.gz

tar -zxvf prozilla-2.0.0-r1.tar.gz
cd prozilla-2.0.0-r1/libprozilla/src/
vi Makefile.in //此发行版的makefle有个小问题
删除第114行
includedir = $(prefix)/include行末的一个空格

cd ../..
./configure --prefix=/usr/apps/prozilla/
make
make install

ln -s /usr/apps/prozilla/bin/proz /usr/bin/proz
使用方法:
Usage: proz [OPTIONS] file_url

Ex: proz http://gnu.org/gnu.jpg

Options:
-h, --help Give this help
-r, --resume Resume an interrupted download
-f, --force Never prompt the user when overwriting files
-1 Force a single connection only
-n, --no-netrc Don't use .netrc, get the user/password
from the command line,otherwise use the
anonymous login for FTP sessions
--no-getch Instead of waiting for the user pressing a key,
print the error to stdout and quit
--debug Log debugging info to a file (default is debug.log)
-v,--verbose Increase the amount of information sent to stdout
--no-curses Don't use Curses, plain text to stdout

Directories:
-P, --directory-prefix=DIR save the generated file to DIR/

FTP Options:
--use-port Force usage of PORT insted of PASV (default)
for ftp transactions

Download Options:
-s, --ftpsearch Do a ftpsearch for faster mirrors
--no-search Do a direct download (no ftpsearch)
-k=n Use n connections instead of the default(4)
--timeout=n Set the timeout for connections to n seconds
(default 180)
-t, --tries=n Set number of attempts to n (default(200), 0=unlimited)
--retry-delay=n Set the time between retrys to n seconds
(default 15 seconds)
--max-bps=n Limit bandwith consumed to n bps (0=unlimited)

FTP Search Options:
--pt=n Wait 2*n seconds for a server response (default 2*4)
--pao=n Ping n servers at once(default 5 servers at once)
--max-ftps-servers=n Request a max of n servers from ftpsearch (default 40)
--min-size=n If a file is smaller than 'n'Kb, don't search, just download it
--ftpsid=n The ftpsearch server to use
(0=filesearching.com
1=ftpsearch.elmundo.es

Information Options:
-L, --license Display software license
-V, --version Display version number

ProZilla homepage: http://prozilla.genesys.ro
Please report bugs to <prozilla@genesys.ro>

由 beat 发表于 下午03点54分 | 回复 (0)

2005年10月14日 星期五

SuSE10调整屏幕偏移和分辨率

在我的机器上装SuSE10以后,进入gnome桌面环境后,屏幕是偏向右侧的。如果这时用显示器下面的自动调整的话,可以调整到合适的状态,但是回到console模式下面就向左偏移了。修改方法是:
1.在console模式下自动调整到最佳位置;
2.startx进入X环境,命令行xvidtune进行调整(这时,可以用显示器的自动调整键),调整好以后,点xvidtune的show按钮,在终端中会显示以下类似信息:
[18:13:28 @Huang ~]#xvidtune
Vendor: --> VESA, Model: 1024X768@60HZ
Num hsync: 1, Num vsync: 1
hsync range 0: 31.00 - 48.00
vsync range 0: 50.00 - 60.00
"1024x768" 65.00 1024 1064 1200 1344 768 771 777 806 -hsync -vsync
3.修改文件/etc/X11/xorg.conf
找到Section "Modes"的位置,添加或修改一行Modeline 为上面得到的数字,并将其他Modeline行注释或删掉,得到类似下面的结果:
Section "Modes"
Identifier "Modes[0]"
Modeline "1024x768" 65.0 1024 1064 1200 1344 768 771 777 806 -hsync -vsync
#Modeline "1024x768" 61.89 1024 1080 1184 1344 768 769 772 794
EndSection
保存,退出。
退出X环境重新进入就可以了。

由 beat 发表于 下午04点07分 | 回复 (0)

2005年10月13日 星期四

提示符

\u - 当前用户的用户名(=$LOGNAME)
\h - 运行shell 的计算机名(hostname)
\H - 完整的计算机名
\W - 当前工作目录名
\w - 当前工作命令全路径名
\$ - 对于普通用户显示$ ,对于超级用户显示#
\! - 当前命令的历史编号
\# - 当前命令编号(在当前的shell 下运行的命令)
\d - 当前日期
\t - 当前时间(24 小时制)
\T - 当前时间(12 小时制),bash 2.0 有效
\@ - 当前时间(AM/PM 格式),bash 2.0 有效
\s - shell 的类型
\a - 告警声音
\j - 用户的任务数
\n - 新行
\\ - 反斜杠
\[ - 不可打印字符开始标志
\] - 不可打印字符结束标志
\nnn - ASCII 字符对应的八进制数值
$(date) - date (输出当前日期)命令输出或者其他的命令

由 beat 发表于 上午10点55分 | 回复 (0)

2005年10月10日 星期一

SSH权威指南

第一章 SSH简介
ssh(secure shell)是一种通用,功能强大的基于软件的网络安全解决方案,计算机每次向网络
发送数据时,SSH都会自动对其进行加密。数据到达目的地时,SSH自动对加密数据进行
解密。整个过程都是透明的。它使用了现代的安全加密算法,足以胜任大型公司的任务繁重
的应用程序的要求。

SSH协议内容涉及认证AUTHENTICATION,加密ENCRYPTION,和网络上传输数据的完整
性INTEGRITY。

SSH特性概述
1、远程登录
$ ssh -l root host.example.com
2、安全文件传输
$ scp myfile metoo@secondacount.com
3、安全执行远程命令,能确保传输的数据安全。
4、密钥和代理
基于密钥的认证方法不用记住多个帐号密码。
5、访问控制,能授权别人访问自已帐号。
6、端口转发
$ ssh -L 3002:localhost:119 xxx.xxx.com

相关安全技术
rsh命令族,rsh,rlogin and rcp。连接不加密,认证模型十分脆弱。
PGP加密程序。它是基于文件的。
Kerberos认证系统,用于网络可能被监视,而且计算机不是中心控制的环境。基于麻省理工
学院的Athena项目。它SSH不是,SSH是轻量级的,容易部署。Kerberos使用前必须构建
一些重要基础。
IPSEC,Internet安全协议。
SRP,安全远程密码协议,是Stanford大学开发的。是一种专用的认证协议。
SSL,安全套接字。
stunnel,是一种SSL工具,它为UNIX环境现有的基于TCP的服务(POP,IMAP等)增加
SSL保护,而不用修改服务器源程序。

第二章 SSH客户端的基本用法
最常用功能,1、经由安全连接登录到远程计算机。2、通过安全连接在计算机间拷贝文件。

当你第一次连接SSH服务器时,出现问答时要回答“yes”,把已知名主机的密钥的公共部
分拷贝一份存在本地。之后你每次连接这台服务器,就用这个公钥来验证远程主机。最好是
能在首次连接前就能获得这个公钥,否则第一次连接服务器时你可能已受到中间人攻击。

使用密钥进行认证,SSH支持公钥认证,可以使用加密密钥,密钥比密码更安全。
SSH证书使用一对密钥,一个私钥,一个公钥,私钥只保存你独有的一些秘密信息。SSH
用其向服务器证明自已的身份。公钥是公开的,可以随便将其放入SSH服务器上自已的帐
号中,在认证时,进行私钥和公钥协商,如果匹配,那么身份就得以证明,认证就成功。

在使用公钥认证以前,首先要进行一些设置:
1、需要一对密钥,还需要使用一个口令来保护自已的私钥。
使用ssh-keygen程序生成一对密钥。如果不存在SSH目录,程序为自动创建本地SSH目录
~/.ssh,并将所生成的密钥分成两个文件存储,公有部份identity.pub,私有部分identity,或
id_dsa_1024_a,id_dsa_1024_a.pub(ssh2)。
2、需要在SSH服务器上安装自已的公钥。
通过配置SSH目录中的一个文件实现,对于SSH1 AND OPENSSH来说该文件是
~/.ssh/authorized_keys。对SSH2来说是~/.ssh2/authorization。OPENSSH中的SSH-2连接自
3.0版本起也一同使用authorized_keys文件。3.0版本前的使用authorized_keys2。把用户本
地机器生成identity.pub文件内容加入其中。对SSH2来说,用户需编辑两个文件,一个客
户端一个在服务器端,
在客户端,要创建或编辑文件~/.ssh2/identification并在其中插入一行,说明自已的私钥文件
名: IdKey id_dsa_1024_a.
在服务器端,要创建或编辑文件~/.ssh2/authorization,该文件包含有公钥信息,每行一个,
但和SSH1的authorized_keys文件不同(authorized_keys中包含有公钥的拷贝),authorization
中只给出公钥文件名:Key id_dsa_1024_a.pub。最后,把这个文件从本地机器上拷贝到服务
器~/.ssh2中。为安全起见,要确保ssh目录的安全,只有所有者才有权写入。如果远程用户
的SSH配置文件的权限设置不当,服务器可能会拒绝进行认证。

公钥认证比密码认证更安全,因为:
1、 公钥认证需要两个加密部份(磁盘上的identify文件和用户头脑中的口令),入侵都必须
2、 具备两种条件才行。密码认证只需要一个部份,那就是密码,它可能更容易被窃取。
3、 在公钥认证中,口令和密钥都不用发给远程主机,只要把前面讨论的认证者发给远程主
4、 机就可以了,因此,并没有秘密信息传出客户端。
3、机器生成的密钥是不可能猜测出来的,而人生成的密码容易受到字典攻击。
通过禁用密码认证并只允许使用密钥认证能极大提高主机的安全性。

如果要修改密钥
如果已经生成一个密钥对,并把公钥拷贝到多个SSH服务器上了,用户有一天决定修改自
已的身份,因为再运行ssh-keygen。这样,就会覆盖identify and identify.pub文件,用户之
前的公钥就没用了,必须把新公钥再次拷贝到各个服务器上。这是很头疼的,所以建议:
1、 不能局限于仅仅使用一个密钥对,可随意生一此密钥对,将其保存在不同的文件中,并
2、 将其用作不同的用途。
3、 如果只是想修改口令,就不必重新生成一个密钥对,ssh-keygen有一个命令行选项可以
4、 替换现有的密钥口令。ssh1 and openssh是-p,对于ssh2是-e。这样,因为私钥没变,所以
5、 公钥依然不效,中需使用新口令对私钥进行解密就可以了。

ssh代理
它可以把私钥保存在内存中,为认证提供服务,不用重复输入密码。直到用户退出为止。代
理程序是ssh-agent。可手工运行也可编辑~/.login 或~/.xsession来自动运行。
$ ssh-agent $SHELL 其中SHELL是用户登录shell的环境变量。运行该命令后,打开另外
一个shell,在这个shell中可以访问代理。
接着用ssh-add命令装入私钥。这样,使用ssh and scp命令就不用再提醒输入口令了。口令
装入内存中。如果用户正运行x window系统,并设置了DISPLAY环境变量,而标准输入
不是终端,那么ssh-add就使用一个图形化X程序ssh-askpass来读取口令。要强制ssh-add
使用X来读取口令,请在命令行中输入ssh-add < /dev/null。
-l 参数显示内存中的密钥
-d 参数从代理中删除密钥 $ ssh-add -d ~/.ssh/id_xxx.pub
-D 是删除所有密钥
-t 对加载的密钥设置超时时间,超时代理将自动卸载密钥。
-L -U 对代理进行加锁和解锁,当你离开计算机而不想退出登录时有用。


代理转发
可能通过代理转发功能,可以用SCP把文件从远程SSH服务器上拷贝到第三方SSH主机上。
条件是你在第三方SSH主机上必须有一个帐号。具体操作是这样的:
1、 在本地主机上运行命令:# scp pat@shell.isp.com:print-me
2、 psmith@other.host.net:other-print-me
2、这个scp进程与本地代理进行联系,并让用户和shell.isp.com进行认证。
3、自动在shell.isp.com上执行第二个scp,用来把文件拷贝到other.host.net主机上。
3、 由于启用了代理转发(SSH1 AND SSH2默认是打开的,openssh默认是关闭的),因此
4、 shell.isp.com上的SSH服务器就充当一个代理。
5、第二个scp进程通过联系shell.isp.com上的代理试图让用户和other.host.net进行认证。
5、 shell.isp.net上ssh服务器秘密与用户的本地代理进行通信,从而构建出一个认证者来提
6、 供用户的证书并将其传回服务器。
7、服务器为第二个scp进程验证用户的身份,other.host.net上的认证获得成功。
8、开始拷贝文件。
由于代理转发不会把私钥发送到远程主机上,而是把认证返回第一台机进行处理,因此密钥
是安全的。

不用密码或口令进行连接方式
1、使用代理的公钥认证。
2、可信主机认证。
3、Kerberos认证。
在后文中将会讨论这些方式的优缺点。

sftp
它是在SSH上的一个独立文件传输工具,操作与ftp类似,可以在一个会话中调用多个命令
进行文件拷贝和处理,而scp每次调用时都要打开一个会话。sftp不区分ascii and binary传
输模式,只使用二进制模式,因此,如果使用它在windows and unix之间拷贝ascii文件,
那么就不能正确转换行结束符。

第三章 SSH内幕
SSH协议的主要特性和优点:
1、 使用强加密技术来保证数据的私密性。端到端通信用随机密钥进行加密,随机密钥为会
话进行安全协商,会话结束后被丢弃。支持的算法有ARCFOUR,Blowfish,DES,IDEA,3DES等。
2、通信完整性,确保通信不会被修改。SSH-2基于MD5 AND SHA-1的加密hash算法。
3、认证,即发送者和接收者的身份证明。客户机和服务器双向认证。
4、授权,即对账号进行访问控制。
5、使用转发或隧道技术对其它基于tcp/ip的会话进行加密。支持三种转发,tcp端口转发,
X转发,代理转发。

SSH可以防止的攻击
1、网络窃听,SSH通信是加密的,即使截获会话内容,也不能将其解密。
2、名字服务和IP伪装,SSH通过加密验证服务器主机身份可避免这类风险。
3、连接劫持,SSH的完整性检测负责确定会话在传输过程是否被修改,如果被修改过,就
关闭连接。
4、 中间人攻击,SSH利用两种方法防止这种攻击,第一种是服务器主机认证。除非攻击者
已经成功攻击了服务器主机,获得服务器的私有主机密钥。第二种是限制使用容易受到
这种攻击的认证方法,密码认证容易受到中间人攻击,而公钥和基于主机的/RhostsRSA
则对中间人攻击可以免疫。
5、插入攻击,这种攻击可以客户和服务器之间发送的正文数据流之间插入任意数据。ssh1
1.2.25后和openssh的所有版本都专门进行了设计,来检测并防止这种攻击。这种检测程序
增大了插入攻击的难度,但是并不能完全防止。ssh2使用强加密完整性检测手段来防止这个
问题。可以用3DES算法来防止这种攻击。

SSH不能防止的攻击
1、 密码崩溃,密码认证是一种脆弱的认证形式,尽量使用公钥认证方式。如果必须要密码
认证,可考虑使用S/Key之类的一次性密码机制。
2、 IP AND TCP攻击,由于SSH是在TCP之上进行操作的,因此容易受到针对TCP和IP
缺陷而发起的攻击。SYN flood,TCP不同步和TCP劫持等。只能通过更低层的防护措施
来保护。
3、流量分析。
4、隐秘通道。
5、粗心大意。安全是一个过程,而不是一个产品,不要认为装上SSH就安全了。

第四章 SSH的安装和编译时配置

第五章 服务器范围的配置
sshd可以在三个层次上进行配置,第一层次是上面的安装和编译时配置;第二层次是本章的
服务器范围配置;第三层次是每账号配置(第八章),前者是服务器编译时就指定了包含哪
些特定功能,不包含哪些功能,后者则是由终端用户来修改自已账号所使用的服务器的行为。

以普通用户身份运行SSH服务器
1、得到管理员许可。
2、生成一个主机密钥。
$ ssh-keygen -N '' -b 1024 -f ~/myserver/hostkey 生成hostkey and hostkey.pub两个文件
3、选择端口号。 要选择大于或等1024的端口,因为只有超级用户才有权使用小于
1024的端口 。
4、创建服务器配置文件(可选) 可创建自已的配置文件,否则,服务就使用内建的特性或使
用服务器范围的配置文件。
启动服务器方式:$ sshd -h ~/myserver/hostkey -p 2345 -f ~/myserver/config
由普通用户运行的服务器有一些缺点:
1、由于不是由root的uid下运行,因此只能连接到用户自已的账号上。
2、它需手工调用,不能自启动。
3、 日志用户没权看到,因为服务器把它写到syslog日志系统中,但可用调试模式运行服务
4、 器,这样信息就显示在终端机上。

服务器配置文件
SSH1 AND OPENSSH的配置文件通常是/etc/sshd_config,而SSH2的配置文件通常是
/etc/ssh2/sshd2_config。

以非缺省的配置文件来调用sshd,可以使用命令 -f 选项。$ sshd -f /usr/local/ssh/my_config。

以*号作为标号的语名都会被sshd忽略。

修改完配置后,修改不会马上影响到服务器,可重启服务器或发送SIGHUP信号。$ kill -HUP
`cat /etc/sshd.pid`

如果在命令行改动了配置,用SIGHUP信号重启服务器不能覆盖命令行的配置,它的优先
级高。

主机密钥,sshd主机密钥向SSH客户端唯一地标识SSH服务器。主机密钥保存在一对文件
中,一个文件包含私钥,一个文件包含公钥。对于SSH1 AND OPENSSH,它是
/etc/ssh_host_key。文件位置可用HostKey关键字修改 HostKey /usr/local/ssh/key。服务器的
公钥保存在.pub文件中。
OPENSSH服务器有一个SSH-2的主机密钥,缺省是在/etc/ssh_host_dsa_key。其位置可用
HostDsaKey /usr/local/openssh/key2修改。

对于SSH2,如果服务器是由超级用户运行,缺省私钥文件是/etc/ssh2/hostkey。如果是其它
用户运行,则在~/.ssh2/hostkey。可用HostKeyFile /etc/local/ssh/key修改。公钥是hostkey.pub
文件,可用publicHostKeyFile关键字修改。

可以用命令行选项指定私钥文件:$ sshd -h /usr/local/ssh/key。

随机数种子文件
如果用户的系统中有一个随机位源,如/dev/urandom,那么OPENSSH就不能创建随机数种
子文件。

服务器配置文件
通常是/etc/sshd_config /etc/ssh2/ssh2_config,可以用-f 选项重新指定其配置文件。可用于一
台机器运行多个sshd的情况。

每账号认证文件。~/.ssh/authorized_keys 。


文件权限
由于配置文件的权限设置错误,会降低系统的安全性,所以可以设置StrictModes YES/NO
关键字,对sshd的重要文件和目录的权限进行检查,如果检查失败,服务器就拒绝对该用
户的SSH连接。

在多宿主主机上,使用ListenAddress xxx.xxx.xxx.xxx来限制SSH只监听一个网络接口。

空闲连接时间,IdleTimeout xx 如果是0代表什么都不做,保持连接。否则,超时就断开连
接,可以用s,m,h,d,w表示。

KeepAlive YES/NO 可以断开失效的连接,比如客户端崩溃。

失败的登录
LogingGraceTime 60 限定用户必须在60秒内成功进行认证。 0值表禁用。命令行选项用
-g

PasswordGuesses 5 如果连接请求使用密码认证,那么sshd2就只允许客户端尝试五次。
(SSH2)

限制并发连接
MaxConnections 32 最大32个连接(SSH2)

逆向IP映射
SSH2服务器可以根据客户端地址进行逆向DNS查询,以确保客户端的地址就是这个地址。
如果检查失败,连接拒绝。
RequireReverseMapping yes (ssh2)

转发
AllowTcp-Forwarding yes
X11Forwarding yes

服务器密钥生成
该密钥用来对客户端/服务器之间的通信进行保护。是临时的,永远不会保存在磁盘上。服
务器在启动时生成这个密钥。并以固定的周期重新生成。缺省长度是768位,最小为512,
可以ServerKeyBits 2048 指定长度。用KeyRegenerationInterval 1200指定周期。 命令行选
项:-k

加密算法
Ciphers any 允许所有支持算法。其它算法包括
3des-cbc,blowfish-cbc,twofish-cbc,arcfour,none

mac算法
MAC关键字可以让用户选择sshd2进行完整性检测所使用的算法,称为消息认证代码。用
于sshd2的有hmac-sha1,hmac-md5,hmac-md5-96。

在OPENSSH中,用户可以用Protocol关键字选择支持SSH-1 AND SSH-2,1 代表SSH-1,2 代
表SSH-2, 1,2 代表都支持。

允许用户登录:认证和访问控制
1、认证负责对发起连接请求的用户的身份进行验证。
密码认证
PasswordAuthentication yes AllowedAuthentications password (ssh2)
公钥认证
RSAAuthentication yes (ssh1,openssh/1)
AllowedAuthentications publickey (ssh2)
DEAAuthentication yes (openssh/2)
Rhosts认证,可信主机认证通过检查远程主机名和相关用户名来实现对客户端的身份认证。
RhostsAuthentication yes (ssh1,openssh)
IgnoreRhosts yes (ssh1,ssh2,openssh)不使用系统的hosts.equiv and ~/.rhosts,使用SSH专用
的/etc/shosts.equiv and ~/.shosts
强可信主机认证。
RhostsRSAAuthentication yes ssh1,openssh
AllowedAuthentications hostbased ssh2
提取已知名主机的公钥
UserKnownHosts no ssh2
IgnoreUserKnownHosts yes openssh
PGP认证
Kerberos认证
S/key认证
SecurID认证
PAM认证

2、访问控制负责允许或禁止来自特定用户、机器在或INTERNET域的SSH连接到服务器
上。
通常,只要设置正确,任何账号都可以接收SSH连接,这种访问权限可以使用服务器关键
字AllowUsers and DenyUsers覆盖。
AllowUsers smith
如果配置文件中单独出现一个AllowUsers,后面没有任何内容,就表示禁止所有没提到的用
户连接,如果没有AllowUsers这个关键字,则所有用户都可连接。DenyUsers表示禁止连接。
可用通配符,

可以用组访问控制AllowGroups DenyGroups

主机名访问控制
AllowHosts hostname
DenyHosts hostname

超级用户的访问控制
sshd对超级用户专门使用一种特殊的访问机制,PermiRootLogin来允许或禁止使用SSH来
访问root账号。

显示用户的欢迎信息
PrintMotd yes/no default is yes

显示邮件信息
CheckMail yes/no default is yes

空密码
PermitEmptyPasswords yes/no 如果使用密码认证,并且有个账号没有设定密码,那么服务
器就可以拒绝访问这个账号

如果系统中存在/etc/nologin,那么sshd就只允许root用户登录,其它都不能登录。因此,touch
/etc/nologin是把访问权只授给系统管理员的一种快速方法。这样并不需要重新配置ssh。也
不需要重启ssh。

子系统
定义和调用远程命令的一个抽象层,用户可以通过在客户端命令行中给出命令来调用远程命
令,如:ssh server.examply.com /bin/tar c /home 这个命令调用tar,远程把/home拷贝到磁带上。
子系统是服务器机器上预定义的一组远程命令,这样就可以方便地执行。在服务器配置文档
中定义:subsystem backups /bin/tar c /home,要在服务器上运行该命令,可以使用 -s 选项。
ssh -s backups server.example.com。缺省情况下,sshd_config中定义了一个子系统,subsystem
sftp 。不要删除这个子系统,这是scp2和sftp必须的。

日志
Fascisl Logging mode 把调试信息打印到系统日志文件中,可以使用FascistLogging关键字
启用。
调试模式 可以使用-d命令选项启用
安静模式 只能输出严重错误,而不能输出 普通日志,可以使用QuietMode关键字或-q
命令行启用。
openssh中的日志配置关键字是SyslogFacility and LogLevel。SyslogFacility设置syslog的
facility(KERN,DAEMON,USER,AUTH,MAIL等),LogLevel记录日志提供的详细程度,该
值从低到高顺序是:QUIET,FATAL,ERROR,INFO,VERBOSE,DEBUG,使用DEBUG会侵犯用
户的隐私权,这个级别只能用于诊断,而不能用于普通操作。


第六章 密钥管理与代理
一个身份标识由两部份组成,分别称为私钥(Private Key)和公钥(Public Key),合称一个
密钥对。

SSH1,SSH2 AND OPENSSH身份标识文件的格式各不相同。
SSH1缺省设置中,私钥存储在文件identity中,公钥存储在文件identity.pub中。这个密钥
对存放在~/.ssh目录下,在使用前,把公钥拷贝到服务器上的一个认证文件里,如SSH1 AND
OPENSSH中的~/.ssh/authorized_keys,此后,当客户请求连接到你的服务器上的帐号时,就
会用一个私钥作为证明身份的标识,服务器则在authorized_keys文件中寻找与之匹配的公
钥。

SSH2密钥对文件的命名通常是根据该密钥使用的加密算法的性质来起的,例如一个用DSA
加密的1024位密钥生成时其缺省文件名是id_dsa_1024_a and id_dsa_1024_a.pub。用户必须
把私钥放在identification文件中,缺省是~/.ssh2/目录,一个私钥在这个文件中占一行,在公
钥认证中,每一行的开头都有一个关键字IdKey,后跟一个私钥文件名。如:
IdKey id_dsa_1024_a
IdKey my-other-ssh2-key
在服务器端的认证文件~/.ssh2/authorization中,SSH2不包含公钥的实际拷贝,只是把公钥
文件列出来,前面用关键字kEY标识。如:
Key id_dsa_1024_a.pub
Key something-else.pub
这样维护起来更容易,更方便。

OPENSSH对SSH-1连接使用的标识和授权文件与SSH1完全相同,对于SSH-2连接,缺省
的密钥则存储在~/.ssh/id_dsa(private key)和~/.ssh/id_dsa.pub(public key)中,服务器上的授权
文件是~/.ssh/authorized_keys。

创建身份标识用ssh-keygen命令。

OPENSSH的ssh-keygen可以支持SSH1中相应程序的所有功能和选项,它还新增了为SSH-2
连接生成DSA密钥的能力。
$ ssh-keygen -t dsa -b 1024
-e -x 选项可把OPENSSH格式的密钥存储格式转换成SSH2格式 (直接回车,按提示输入转
换文件名)
-i -X 选项把SSH2格式的密钥转换成OPENSSH格式。这样可用SSH2客户端连接
OPENSSH服务器。(直接回车,按提示输入转换文件名)
-y 如果不小心删掉了OPENSSH的公钥,可用-y恢复。
-l 可计算出公钥的指纹,指纹是鉴别位置不同的两个密钥是否相同的常用的一种密码学技
术。这项技术用于不可能逐位对比两个密钥的情况。OPENSSH AND SSH2都能计算指纹。
它是根据密钥计算出来一个长度较短的值,它是原理与校验和类似,用于验证一串信息(在
我们的例子中是密钥)的不可替换性。

启动代理
1、单shell方式,使用当前登录的shell. $ eval `ssh-agent`
2、子shell方式,派生出一个子shell,并继承父shell的某些环境变量。 $ ssh-agent $SHELL
不要想当然运行 $ ssh-agent,这样客户端是无法有代理联系的。删除代理用kill命令就可以
了。

SSH-1 与 SSH-2代理的兼容性
SSH-1的代理不能处理SSH-2的代理,SSH-2的代理却可以处理SSH-1的代理请求。

第七章 客户端的高级用法
$ ssh -a -p 220 -c blowfish -l sally -i myself server.example.com 可通过配置文件简化命令
输入

Host myserver
ForwardAgent no
Port 220
Cipher blowfish
User sally
IdentifyFile myself
HostName server.example.com
配置了该文件后,就可以在客户端简单地输入
$ ssh myserver

全局文件和本地文件
全局文件通常是由管理员创建的,用来维护整台计算机上的客户行为。该文件通常位于
/etc/ssh_config or /etc/ssh2/ssh2_config。每个客户也可以在自已账号中创建本地客户配置文
件,通常是~/.ssh/config or ~/.ssh2/ssh2_config。本地配置文件优先级高于全局配置文件。命
令行选项的优先级又高于本地配置文件。

scp有关命令参数
-r 递归拷贝目录
-p 保持文件权限和时间戳
-u 拷贝完成后删除源文件
-d 防止覆盖文件
-n 描述操作
-q 不显示统计信息


第八章 每账号服务器配置
这种配置可以让SSH服务器区分每个服务器上的各个用户。利用服务器目标账号的认证文
件(authorized_keys)配置。局限有两点,它不能覆盖编译时配置和服务器范围配置所采用
的安全措施,第二,如果使用公钥认证,每账号配置是十分灵活的,如果采用可信主机和密
码认证,提供的选择范围就很小。

基于公钥的配置
1、认证文件的完全格式 依次包含三项内容,一些选项,公钥和注释。多个选项用逗号分
开。
2、用于限制客户端可以在服务器上调用的程序的强制命令。如客户端请求执行/bin/ls命令,
而服务器端强制命令却运行/bin/who命令,它十分有用,可用于加强安全性,了为授权提供
方便。如要让你的助手每次连接上来都运行email命令程序pine,则可以这样:
command= "/usr/local/bin/pine" ...key...。最多可给每个密钥关联一个强制命令,要关联多个命
令可把这些命令放入远程主机的一个脚本中,并将该脚本作为强制命令运行。如果强制命令
有shell出口,那会存在安全问题,等于没有强制,客户可以运行任何程序。以下规则可以
用来判断一个程序是否适合用作强制命令。
a、 避免使用具有shell出口的程序(如:文件编辑器vi,Emacs; 分页程序 more,less;调用分
b、 页的man,新闻阅读程序rn,邮件阅读程序pine以及调试程序adb,非交互的程序find,xargs
c、 等)。
b、避免使用编译器,解释器或其它可以让用户生成并运行任意执行代码的程序。
c、可创建或删除文件的程序,如cp,mv,rm,scp,ftp等。
d、避免使用setuid or setgid的程序,特别是setuid 是root的程序。
d、 如果使用脚本作为强制命令,就要遵循编写安全脚本的传统规则,在一个脚本之内,要
限制使用相对路径作为搜索路径,应该使用绝对路径来调用所有的程序;不要盲目地把
用户提供的字符串作为命令来执行;不要让脚本执行任何setuid的工作。不要调用具有
shell出口的程序。
e、考虑使用受限shell。
f. 为一个单独的、专用的SSH密钥(不要用你登录的那个密钥)关联一个强制命令。这样
不会影响你的登录能力就可以方便地禁用该密钥。
g、禁用不必要的SSH特性。如no-port-forwarding,no-agent-forwarding,no-pty(禁用tty分配)。
几个常用的强制命令介绍:
使用定制消息拒绝连接:command="/bin/echo Sorry,buddy,but you've terminated!" ...key... 千万
不要用more and less之类的分页程序
显示命令菜单:利用脚本
检查客户端的原始程序:command="/bin/echo you tried to invoke
$SSH_ORIGINAL_COMMAND" ...key... $SSH_ORIGINAL_COMMAND环境变量保存着
客户连接时运行的原始命令。
限制客户端的原始命令,创建一个脚本,该脚本根据$SSH_ORIGINAL_COMMAND内容选
择不同的操作。
把客户端的原始命令记录在日志中:也是根据$SSH_ORIGINAL_COMMAND变量来做的一
个脚本。脚本内容如一:
#!/bin/sh
if [ -n "$SSH_ORIGINAL_COMMAND" ]
then
echo "`/bin/date`: $SSH_ORIGINAL_COMMAND" >> $HOME/ssh-command-log
exec $SSH_ORIGINAL_COMMAND
fi

3、限制来自特定主机的连接。由from选项完成。from="client.example.com" ...key...。强制
连接必须来自client.example.com。否则断开。from="!client.example.com" ...key...表示拒绝该
地址的连接。支持通配符。SSH2不支持该功能。但可以通过$SSH2_CLIENT变量提取客户
ip,编写强制命令脚本达到同样效果。
4、为远程程序设置环境变量。environment="EDITOR=emacs" ...key...,为每个连接修改默认的
环境变量。
5、设置空闲超时时间,这样如果客户端用户不再发送数据就强制将其断开。idle-timeout=5m,
该选项会覆盖服务器范围配置。
6、对到达的SSH连接禁用某些特性,例如端口转发和tty分配。禁用tty分配会使客户端没
有交互会话的能力。$SSH_TTY变量可显示tty情况。

用户的rc文件
ssh服务器会在每个连接到达时调用shell脚本/etc/sshrc,用户可把一些登录后想运行的脚本
写到这个文件中。用户可以在自已的目录下定义类似的脚本,如果有自定义的~/.ssh/rc则
/etc/sshrc则不会执行。

第九章 端口转发与X转发
使用SSH对其它应用程序在别的TCP端口上建立的TCP/IP传输进行加密和解密,这一过
程称为端口转发,其绝大多数操作都是透明的,功能非常强大。TELNET,SMTP,NNTP,IMAP
和一些基于TCP的不安全协议都可变得安全,只要将其连接通过SSH转发即可。端口转发
有时又叫做隧道传输。
例子:一个运行IMAP的服务器S,在家里的主机H上运行一个email程序,现在想用ssh
保护IMAP连接。
$ ssh -L2001:localhost:143 S
-L 表明是本地转发,,上面这命令可完成登录到S的功能,现在的这个SSH会话同时将H
的2001端口转发到S的143端口,在退出会话之前一直有效。并告知email程序使用被转
发的端口,通常邮件程序连接服务器的143端口,即套接字 (S,143)。现在要令其连接
本地主机H自已的2001端口,也就是套接字(localhost,2001)。创建本地转发时可以不用-L
选项,而在客户端配置文件中用LocalForward关键字。
LocalForward 2001 localhost:143 ssh1 openssh
LocalForward "2001:localhost:143" ssh2

-g 选项和GatewayPorts yes/no关键字可以配置除本地主机外的机器是否能使用本地的端口
转发功能。出于安全问题,该禁止这个功能。

远程转发端口与本地转发几乎完全相同,只是方向相反。此时服务器在本地,转发连接由远
程主机发起。假设你已登录进服务器S。则
$ ssh -R2001:localhost:143 H
-R代表远程转发。命令执行后,一条从远程主机H的2001端口到服务器S的143端口的安
全隧道就建立起来了。H上的任何程序都可以通过连接(localhost,2001)来使用此安全隧道。
而在客户端配置文件中用RemoteForward关键字.
RemoteForward 2001 S:143 ssh openssh
RemoteForward "2001:S:143" ssh2

$ ssh -o ClearAllForwardings=yes server.example.com 阻止第二条命令建立隧道

本地转发与远程转发
在本地转发中,应用程序客户端与监听端同SSH客户端在一起,应用程序服务器与连接端
同SSH服务器在一起。
在远程转发中,应用程序客户端与监听端同SSH服务器在一起,应用程序服务器与连接端
同SSH客户端在一起。

无远程登录的端口转发,连接时带-f参数。一次性转发用-fo,ssh1与openssh不支持这个功
能,但可用以下语句实现:
$ ssh -f -L2001:localhost:143 server sleep 10

终止
如果一个SSH会话现在还在活动当中,终止会出错。在SSH2中,如果退出有活动转发连
接的会话,该会话会依然打开,但会转到后台运行。直到转发连接终止。ssh1 and openssh
与此相反,如果要断开还在活动的会话,会出现警告,仍然在前台运行。

TIME_WAIT问题。在某些情况下,TCP连接断连时,其一端的套接字在很短一段时间内变
得不可用,所以在断连过程结束前不能把该端口用于TCP转发。


第十章 推荐配置
服务器范围配置
1、禁用其它访问方式。
关掉r-命令,方法如下:删除/etc/hosts.equiv文件,或改为只读空文件。禁用rshd,rlogind and
rexecd,通过修改inetd.conf文件。
2、/etc/sshd_config配置
HostKey /etc/ssh_host_key
PidFile /etc/sshd.pid
RandomSeed /etc/ssh_random_seed

StrictModes yes 要求用户保护其与SSH有关的文件及目录
Umask 0077 保证所有SSHD1创建是文件和目录都只能由其所有者(SSHD 运行的
UID)读取

port 22
ListenAddress 0.0.0.0
IdleTimeout 15m 15分钟空闲超时
KeepAlive yes 客户机死机时连接将会终止,而不会长期挂起。

LoginGraceTime 30 登录时成功认证的时限为30秒。

ServerKeyBits 768 服务器密钥长度
KeyRegenerationInterval 3600 服务器密钥一小时重新生成一次

PasswordAuthentication no 禁用密码认证
RhostsAuthentication no 禁用可信主机认证
RhostsRSAAuthentication no 禁用增强可信主机认证
RSAAuthentication yes 启用公钥认证

IgnoreRhosts yes 完全禁止SSHD使用.rhosts文件
IgnoreRootRhosts yes

UseLogin no 禁用UseLogin,防止万一使用了其它登录程序

AllowHosts xxx 根据需要设置
SilentDeny yes 任何被DenyHosts拒绝的连接都不会向用户返回消息,不必告诉攻击
者发生了什么,可以增加了排错的难度。

PermitRootLogin nopwd 允许超级用户通过SSH连接,但不能用密码认证

FascistLogging no 禁用FascistLogging日志方式,因为它会在日志中记录用户特定信息,对
攻击者有用。
QuietMode no 禁用QuietMode日志方式,使用日志更详细,敏感度更低

AllowTcpForwarding yes 允许tcp端口转发和X转发,保护其它的tcp连接
X11Forwarding yes

3、/etc/ssh2/sshd2_config配置
HostKeyFile /etc/ssh2/hostkey
PublicHostKeyFile /etc/ssh2/hostkey.pub
RandmoSeedFile /etc/ssh2/random_seed

UserConfigDirectory
IdentityFile
AuthorizstionFile

StrictModes yes

port 22
listenAddress 0.0.0.0
KeepAlive yes
RequireReverseMapping no

LoginGraceTime 30

由于sshd2没有设置服务器密钥的位数的关键字,用户得在启动时使用 -b 选项 $ sshd2 -b
1024 ....

AllowedAuthentications publickey
RequiredAuthentications publickey

IgnoreRhosts yes
UserKnownHosts no 禁用该项可防止用户给未知主机提供信任权限。

PermitRootLogin nopwd


Ciphers any 不能选none


QuietMode no
VerboseMode yes

Ssh1Compatibility no 禁用SSH-1兼容模式
#Ssh1Path /usr/local/ssh1/sshd1 出于实用原因,也可以启用此模式,之前要指明ssh1服
务器可执行文件位置

4、每账号配置
对于SSH1 AND OPENSSH,~/.ssh/authorized_keys中的每一个密钥都必须用适当的选项进
行限制,from选项限制只能从特定的主机访问特定的密钥。例如,假设文件中包含你家那
台pc(myhome.isp.net)的公钥,而其它机器根本不可能用那个密钥来认证,我们就可以明确
限定这一关系:from = "myhome.isp.net" ...key...。还要对适当的密钥设置空闲超时时间:from
= "myhome.isp.net" ,idle-timeout=5m ...key...。
最后,考虑每一个密钥是否需要对到达的连接使用端口转发,代理转发以及分配tty等,如
果不需要,就可以分别用no-port-forwarding,no-agent-forwarding and no-pty禁用这些特性。

5、密钥管理
至少创建1024位长的用户密钥,并用好的口令对密钥进行保护。

6、客户端配置
离开正在运行的ssh客户端时,一定要用密码保护。
在客户端配置文件中启用某些安全功能,并将其设置为最强
Host *
FallBackToRsh no 禁止使用不安全的r-命令(ssh2)没有这个问题。
UseRsh no
GatewayPorts no 禁止远程客户端连接本地的转发端口
StrictHostKeyChecking ask 在主机密钥发生变化时提醒你。请求你的处理意见。
配置“/etc/ssh/ssh_config”文件 
“/etc/ssh/ssh_config”文件是OpenSSH系统范围的配置文件,允许你通过设置不同的选项
来改变客户端程序的运行方式。这个文件的每一行包含“关键词-值”的匹配,其中“关键
词”是忽略大小写的。下面列出来的是最重要的关键词,用man命令查看帮助页(ssh (1))
可以得到详细的列表。 

编辑“ssh_config”文件(vi /etc/ssh/ssh_config),添加或改变下面的参数: 

# Site-wide defaults for various options 
Host * 
ForwardAgent no 
ForwardX11 no 
RhostsAuthentication no 
RhostsRSAAuthentication no 
RSAAuthentication yes 
PasswordAuthentication yes 
FallBackToRsh no 
UseRsh no 
BatchMode no 
CheckHostIP yes 
StrictHostKeyChecking no 
IdentityFile ~/.ssh/identity 
Port 22 
Cipher blowfish 
EscapeChar ~ 

下面逐行说明上面的选项设置: 

Host * 
选项“Host”只对能够匹配后面字串的计算机有效。“*”表示所有的计算机。 

ForwardAgent no 
“ForwardAgent”设置连接是否经过验证代理(如果存在)转发给远程计算机。 

ForwardX11 no 
“ForwardX11”设置X11连接是否被自动重定向到安全的通道和显示集(DISPLAY set)。 

RhostsAuthentication no 
“RhostsAuthentication”设置是否使用基于rhosts的安全验证。 

RhostsRSAAuthentication no 
“RhostsRSAAuthentication”设置是否使用用RSA算法的基于rhosts的安全验证。 

RSAAuthentication yes 
“RSAAuthentication”设置是否使用RSA算法进行安全验证。 

PasswordAuthentication yes 
“PasswordAuthentication”设置是否使用口令验证。 

FallBackToRsh no 
“FallBackToRsh”设置如果用ssh连接出现错误是否自动使用rsh。 

UseRsh no 
“UseRsh”设置是否在这台计算机上使用“rlogin/rsh”。 

BatchMode no 
“BatchMode”如果设为“yes”,passphrase/password(交互式输入口令)的提示将被禁止。
当不能交互式输入口令的时候,这个选项对脚本文件和批处理任务十分有用。 

CheckHostIP yes 

“CheckHostIP”设置ssh是否查看连接到服务器的主机的IP地址以防止DNS欺骗。建议设
置为“yes”。 

StrictHostKeyChecking no 
“StrictHostKeyChecking”如果设置成“yes”,ssh就不会自动把计算机的密匙加入
“$HOME/.ssh/known_hosts”文件,并且一旦计算机的密匙发生了变化,就拒绝连接。 

IdentityFile ~/.ssh/identity 
“IdentityFile”设置从哪个文件读取用户的RSA安全验证标识。 

Port 22 
“Port”设置连接到远程主机的端口。 

Cipher blowfish 
“Cipher”设置加密用的密码。 

EscapeChar ~ 
“EscapeChar”设置escape字符。 

配置“/etc/ssh/sshd_config”文件 
“/etc/ssh/sshd_config”是OpenSSH的配置文件,允许设置选项改变这个daemon的运行。
这个文件的每一行包含“关键词-值”的匹配,其中“关键词”是忽略大小写的。下面列出
来的是最重要的关键词,用man命令查看帮助页(sshd (8))可以得到详细的列表。 

编辑“sshd_config”文件(vi /etc/ssh/sshd_config),加入或改变下面的参数: 

# This is ssh server systemwide configuration file. 
Port 22 
ListenAddress 192.168.1.1 
HostKey /etc/ssh/ssh_host_key 
ServerKeyBits 1024 
LoginGraceTime 600 
KeyRegenerationInterval 3600 
PermitRootLogin no 
IgnoreRhosts yes 
IgnoreUserKnownHosts yes 
StrictModes yes 
X11Forwarding no 
PrintMotd yes 
SyslogFacility AUTH 
LogLevel INFO 
RhostsAuthentication no 
RhostsRSAAuthentication no 
RSAAuthentication yes 
PasswordAuthentication yes 
PermitEmptyPasswords no 
AllowUsers admin 

下面逐行说明上面的选项设置: 

Port 22 
“Port”设置sshd监听的端口号。 

ListenAddress 192.168.1.1 
“ListenAddress”设置sshd服务器绑定的IP地址。 

HostKey /etc/ssh/ssh_host_key 

“HostKey”设置包含计算机私人密匙的文件。 

ServerKeyBits 1024 
“ServerKeyBits”定义服务器密匙的位数。 

LoginGraceTime 600 
“LoginGraceTime”设置如果用户不能成功登录,在切断连接之前服务器需要等待的时间(以
秒为单位)。 

KeyRegenerationInterval 3600 
“KeyRegenerationInterval”设置在多少秒之后自动重新生成服务器的密匙(如果使用密匙)。
重新生成密匙是为了防止用盗用的密匙解密被截获的信息。 

PermitRootLogin no 
“PermitRootLogin”设置root能不能用ssh登录。这个选项一定不要设成“yes”。 

IgnoreRhosts yes 
“IgnoreRhosts”设置验证的时候是否使用“rhosts”和“shosts”文件。 

IgnoreUserKnownHosts yes 
“IgnoreUserKnownHosts”设置ssh daemon是否在进行RhostsRSAAuthentication安全验证
的时候忽略用户的“$HOME/.ssh/known_hosts” 

StrictModes yes 
“StrictModes”设置ssh在接收登录请求之前是否检查用户家目录和rhosts文件的权限和所
有权。这通常是必要的,因为新手经常会把自己的目录和文件设成任何人都有写权限。 

X11Forwarding no 
“X11Forwarding”设置是否允许X11转发。 

PrintMotd yes 
“PrintMotd”设置sshd是否在用户登录的时候显示“/etc/motd”中的信息。 

SyslogFacility AUTH 
“SyslogFacility”设置在记录来自sshd的消息的时候,是否给出“facility code”。 

LogLevel INFO 
“LogLevel”设置记录sshd日志消息的层次。INFO是一个好的选择。查看sshd的man帮
助页,已获取更多的信息。 

RhostsAuthentication no 
“RhostsAuthentication”设置只用rhosts或“/etc/hosts.equiv”进行安全验证是否已经足够了。 

RhostsRSAAuthentication no 
“RhostsRSA”设置是否允许用rhosts或“/etc/hosts.equiv”加上RSA进行安全验证。 

RSAAuthentication yes 
“RSAAuthentication”设置是否允许只有RSA安全验证。 

PasswordAuthentication yes 
“PasswordAuthentication”设置是否允许口令验证。 

PermitEmptyPasswords no 
“PermitEmptyPasswords”设置是否允许用口令为空的帐号登录。 

AllowUsers admin 
“AllowUsers”的后面可以跟着任意的数量的用户名的匹配串(patterns)或user@host这样
的匹配串,这些字符串用空格隔开。主机名可以是DNS名或IP地址。 

由 beat 发表于 下午11点30分 | 回复 (0)

2005年10月09日 星期日

快捷方式去掉箭头

regedit进入注册表,
删除
HKEY-LOCAL-MACHINE\Software\CLASSES\lnkfile\IsShotcut

HKEY-LOCAL-MACHINE\Software\CLASSES\piffile\IsShotcut
即可。

由 beat 发表于 下午09点26分 | 回复 (0)

2005年10月08日 星期六

SSH使用及协议分析(转载)

SSH是一个用来替代TELNET、FTP以及R命令的工具包,主要是想解决口令在网上明文传输的问题。为了系统安全和用户自身的权益,推广SSH是必要的。SSH有两个版本,我们现在介绍的是版本2。

安装SSH

具体步骤如下:

获得SSH软件包。 (ftp://ftp.pku.edu.cn:/pub/unix/ssh-2.3.0.tar.gz)

成为超级用户(root).

# gzip –cd ssh-2.3.0.tar.gz |tar xvf –

# cd ssh-2.3.0

# ./configure

注意,如果你希望用tcp_wrappers来控制SSH,那么在configure时需要加上选项“--with-libwrap=/path/to/libwrap/”, 用来告诉SSH关于libwrap.a 和tcpd.h的位置。

# make

# make install

和SSH有关的程序都放置在/usr/local/bin下,包括ssh,sftp,sshd2, ssh-keygen等。

二、配置

SSH的配置文件在/etc/ssh2下,其中包括sshd2的主机公钥和私钥:hostkey和hostkey.pub。这两个文件通常是在安装SSH时自动生成的。你可以通过下面的命令重新来生成它们:

# rm /etc/ssh2/hostkey*

# ssh-keygen2 –P /etc/ssh2/hostkey

而ssh2_config 文件一般情形下无需修改。

三、启动sshd2

每个要使用SSH的系统都必须在后台运行sshd2。用手工启动:

# /usr/local/bin/sshd2&

可以在“/etc/rc2.d/S99local”中加入该命令,这样系统每次启动时会自动启动sshd2。

四、用tcp_wrappers控制SSH

安装SSH的站点可以用tcp_wrappers来限制哪些IP地址可以通过ssh来访问自己。比如,在/etc/hosts.allow中加入

sshd,sshd2: 10.0.0.1

那么只有10.0.0.1可以通过ssh来访问该主机。

以上都是系统管理员完成的工作。下面我们说说普通用户如何使用SSH。

五、基本应用

每个用户在使用SSH之前,都要完成以下步骤:

在本地主机(比如,local.pku.edu.cn)上生成自己的ssh公钥和私钥。命令如下:

local# ssh-keygen

Generating 1024-bit dsa key pair

1 oOo.oOo.o

Key generated.

1024-bit dsa, teng@ns, Fri Oct 20 2000 17:27:05

Passphrase :************ /*在此输入你的口令,以后访问这台主机时要用。

Again :************ /*

Private key saved to /home1/teng/.ssh2/id_dsa_1024_a

Public key saved to /home1/teng/.ssh2/id_dsa_1024_a.pub


生成的私钥和公钥(id_dsa_1024_a和id_dsa_1024_a.pub)存放在你家目录的~/.ssh2目录下。和用户相关的SSH配置文件都在~/.ssh2下。私钥由用户保存在本地主机上,而公钥需传送到远地主机的你自己的帐号的~/.ssh2下,如果你要用ssh2访问本地主机的话。


在~/.ssh2下创建“identification”文件用来说明进行身份认证的私钥。命令如下:


local:~/.ssh2# echo "IdKey id_dsa_1024_a" > identification


3.同样地,在远地主机(比如,remote.pku.edu.cn)上完成上面步骤。

4.将本地(local.pku.edu.cn)下你自己(这里是“teng”)的公钥(id_dsa_1024_a.pub)拷贝到远地主机(remote.pku.edu.cn)上你自己家目录下的.ssh2目录下,可命名为“local.pub”,一般用ftp上传即可。


在远地主机上,你自己家目录的.ssh2目录下,创建“authorization”文件,其中指定用来进行身份认证的公钥文件。命令如下:

remote:~/.ssh2# echo “Key local.pub” > authorization


现在你可以从本地用ssh2登录到远地系统了。命令如下:

local# ssh remote.pku.edu.cn

Passphrase for key "/home1/teng/.ssh2/id_dsa_1024_a" with comment "1024-bit dsa,

teng@ns, Fri Oct 20 2000 17:27:05":***********


这时会要你输入你的ssh口令(Passphrase)。验证通过后,即登录到remote主机上。


第一部分:协议概览

整个通讯过程中,经过下面几个阶段协商实现认证连接。

第一阶段:

由客户端向服务器发出 TCP 连接请求。TCP 连接建立后,客户端进入等待,服务器向客户端发送第一个报文,宣告自己的版本号,包括协议版本号和软件版本号。协议版本号由主版本号和次版本号两部分组成。它和软件版本号一起构成形如:

"SSH-<主协议版本号>.<次协议版本号>-<软件版本号>\n"

的字符串。其中软件版本号字符串的最大长度为40个字节,仅供调试使用。客户端接到报文后,回送一个报文,内容也是版本号。客户端响应报文里的协议版本号这样来决定:当与客户端相比服务器的版本号较低时,如果客户端有特定的代码来模拟,则它发送较低的版本号;如果它不能,则发送自己的版本号。当与客户端相比服务器的版本号较高时,客户端发送自己的较低的版本号。按约定,如果协议改变后与以前的相兼容,主协议版本号不变;如果不相兼容,则主主协议版本号升高。

服务器接到客户端送来的协议版本号后,把它与自己的进行比较,决定能否与客户端一起工作。如果不能,则断开TCP 连接;如果能,则按照二进制数据包协议发送第一个二进制数据包,双方以较低的协议版本来一起工作。到此为止,这两个报文只是简单的字符串,你我等凡人直接可读。

第二阶段:

协商解决版本问题后,双方就开始采用二进制数据包进行通讯。由服务器向客户端发送第一个包,内容为自己的 RSA主机密钥(host key)的公钥部分、RSA服务密钥(server key)的公钥部分、支持的加密