自己的一个控制登陆的程序
发表于:2007-05-26来源:作者:点击数:
标签:
看到不少关于如何控制 网络 登陆的好帖子 这里贴个自己写的在本人所在单位使用的东东 还请高人指正 [code:1:d719df063a] /*mytcpwrap.c 功能:类似著名的tcpwrap 根据配置文件,允许某些地址的用户进行登陆连接 除可记录登陆时间外,还可以记录退出时间 本程
看到不少关于如何控制
网络登陆的好帖子
这里贴个自己写的在本人所在单位使用的东东
还请高人指正
[code:1:d719df063a]
/* mytcpwrap.c
功能:类似著名的 tcpwrap
根据配置文件,允许某些地址的用户进行登陆连接
除可记录登陆时间外,还可以记录退出时间
本程序应由超级
服务器.netd启动
使用:替换/etc/inetd.conf 中要进行控制的端口
以telnet、ftp端口控制为例:
/etc/inetd.conf 原内容:
ftp stream tcp nowait root /etc/ftpd ftpd
telnet stream tcp nowait NOLUID /etc/telnetd telnetd
改为:
ftp stream tcp nowait root /etc/mytcpwrap /etc/ftpd
telnet stream tcp nowait NOLUID /etc/mytcpwrap /etc/telnetd
注意:改完后记得通知一下inetd进程
*/
#include "stdio.h"
#include "errno.h"
#include "time.h"
#include "signal.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "sys/stat.h"
#include "sys/times.h"
#define INET_ADDRESTRLEN 18
#define MAXSOCKADDR 64
/* 地址配置文件
格式 port ips
'#' 打头表示本行为注释
'S' 打头表示网络日志记录地,格式为 S port ips
缺省为 5678 1.1.1.1
接受通配符 *
其中 port 记录本地端口,可以使用通配符 * 表示任意端口
ips 允许访问的远程IP地址,形如 nnn.nnn.nnn.nnn
可以使用通配符 * 表示任意地址
例: 21 1.1.1.1 表示1.1.1.1的机器可以访问本机21(ftp)端口
* 2.2.2.2 表示2.2.2.2的机器可以访问本机任意端口
23 3.3.3.* 表示3.3.3.*网段的机器可以访问本机23(telnet)端口
*/
#define INIFILE "/etc/mytcpwrap.conf"
#define LOGFILE "/usr/adm/mytcpwrap.log"
short R_PORT=5678;
char R_ADDR[16]="1.1.1.1";
/* 简单字符串比较函数 */
int cj_Compare(char *so, char *sd)
{
char *to,*td;
int done,cjOk=0,i,k;
if (*sd==0) return 0;
for (done=0,to=so,td=sd;!done; ) {
if (*td=='?') {
td++; to++;
}
else if (*td=='*') {
if (cj_Compare(to,(td+1))==0) return 0;
else to++;
}
else {
cjOk = done = *to - *td;
td++; to++;
}
if (*to==0) for ( ;(*td=='?')||(*td=='*');td++);
if ((*to==0)&&(*td==0)) break;
else if (*to==0) done = cjOk = -1;
else if (*td==0) done = cjOk = -1;
}
return cjOk;
}
int is_denied(char *s, int lport)
{
int k, ct;
char buf[128], ips[32], pts[8];
FILE *fp;
/* 读配置文件 */
fp = fopen(INIFILE, "rt");
if (fp){
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf)-1, fp);
while (!feof(fp)){
memset(pts, 0, sizeof(pts));
memset(ips, 0, sizeof(ips));
sscanf(buf, "%5s%15s", pts, ips);
if (pts[0]!='#'){
if (pts[0]!='S' && pts[0]!='s'){
/* 去除末尾单独的'.' */
while (ips[strlen(ips)-1]=='.') ips[strlen(ips)-1]=0;
for (ct=k=0;k<strlen(ips);k++)
if (ips[k]=='.') ct++;
/* 补齐 nnn.nnn.nnn.nnn 的格式 */
while (ct<3){
strcat(ips, ".*"); ct++;
}
/* 端口号是否一致或是任意端口 */
if (pts[0]=='*' || atoi(pts)==lport){
/* 比较IP地址是否满足匹配规则 */
if (cj_Compare(s, ips)==0){
fclose(fp);
/* 返回成功--接受登录 */
return 0;
}
}
}
else{
/* 读网络日志服务器地址、端口 */
memset(pts, 0, sizeof(pts));
memset(ips, 0, sizeof(ips));
sscanf(buf, "%*s%5s%15s", pts, R_ADDR);
R_PORT = atoi(pts);
}
}
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf)-1, fp);
}
fclose(fp);
}
/* 未找到匹配记录,拒绝登录 */
return 1;
}
char *inet_ntop(int f, void *a, char *s, int l)
{
u_char *p=(u_char *)a;
struct in_addr inv;
char tt[INET_ADDRESTRLEN];
if (f==AF_INET){
snprintf(tt, sizeof(tt), "%d.%d.%d.%d",p[0], p[1], p[2], p[3]);
if (strlen(tt)>l){
errno = ENOSPC;
return NULL;
}
strcpy(s, tt);
return tt;
}
errno = EAFNOSUPPORT;
return NULL;
}
sock_ntop(struct sockaddr * sa, int len, char *s)
{
char str[128];
int pt=-1;
struct sockaddr_in *sin=(struct sockaddr_in *)sa;
s[0] = 0;
switch(sa->sa_family){
case AF_INET:if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))==NULL)
return NULL;
pt = ntohs(sin->sin_port);
strcpy(s, str);
break;
};
return pt;
}
get_time(int t[6])
{
struct tm *tm;
time_t n;
n = time(NULL);
tm = localtime(&n);
t[0] = tm->tm_year + 1900;
t[1] = tm->tm_mon+1;
t[2] = tm->tm_mday;
t[3] = tm->tm_hour;
t[4] = tm->tm_min;
t[5] = tm->tm_sec;
}
long rowid=0;
/* 将登录信息记录到网络上日志服务器上
通过两次提交记录完整的登陆、退出时间
第一次记录登录时间
发送格式: NETLOG|本地服务端口|客户地址|端口|成功标志|
服务端返回一个该记录的rowid值
第二次记录离开时间
发送格式: NETUPD|原记录的rowid
*/
int net_logit(int lport, char *ips, int rport, int su
clearcase/" target="_blank" >cc)
{
int i,s;
struct sockaddr_in sin;
struct hostent *hp;
char buf[128], ss[64];
if (R_PORT==0 || strlen(R_ADDR)==0) return -1;
bzero((char *)&sin,sizeof(sin));
sin.sin_family = AF_INET;
/* 取日志服务器地址 */
hp = gethostbyname(R_ADDR);
if (hp!=NULL)
bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
else
inet_aton(R_ADDR, &sin.sin_addr);
sin.sin_port = htons(R_PORT);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s<0) return 1;
/* 连接日志服务器 */
if ((i=connect(s, (struct sockaddr *)&sin,sizeof(sin)))<0){
close(s);
return 2;
}
/* 发送日志信息 格式: NETLOG|本地服务端口|客户地址|端口|成功标志| */
/* 第一次记录登录时间 */
if (rowid==0)
sprintf(ss, "NETLOG|%d|%s|%d|%d|", lport, ips, rport, succ);
else
/* 第二次记录离开时间,发送信息格式: NETUPD|原记录的rowid */
sprintf(ss, "NETUPD|%d|", rowid);
sprintf(buf, "%04d%s", strlen(ss), ss);
write(s, buf, strlen(buf));
memset(ss, 0, sizeof(ss));
if (rowid==0){
/* 取该记录的rowid */
read(s, ss, sizeof(ss)-1);
rowid = atol(ss);
}
/* 关闭连接 */
shutdown(s, 2);
close(s);
return 0;
}
void mysig(int sig)
{
return ;
}
main(int argc, char *argv[], char *envp[])
{
int srq[6], i, ct, k, rport, lport;
unsigned int len;
char buf[128], ips[32];
FILE *fp;
union{
struct sockaddr sa;
char data[MAXSOCKADDR];
}from;
/* 取本地端口 */
len = sizeof(from);
k = getsockname(1, (struct sockaddr *)&from.data, &len);
lport = sock_ntop(&from.sa, len, ips);
/* 取远程端口、地址 */
len = sizeof(from);
k = getpeername(1, (struct sockaddr *)&from.data, &len);
rport = sock_ntop(&from.sa, len, ips);
get_time(srq);
sprintf(buf, "端口 %d, 来自 %15s:%d, 时间 %04d/%02d/%02d %02d:%02d:%02d ",
lport, ips, rport, srq[0], srq[1], srq[2],
srq[3], srq[4], srq[5]);
fp = fopen(LOGFILE, "at");
if (fp!=NULL)
fprintf(fp, "%s", buf);
k = is_denied(ips, lport);
/* 记录登录时间 */
net_logit(lport, ips, rport, k);
if (k){
fprintf(stderr,"对不起,您没有在此主机登录的权限!\007\r\n");
if (fp!=NULL){
fprintf(fp, "...拒绝[%d]!\n", rowid);
fclose(fp);
}
exit(1);
}
if (fp){
fprintf(fp, "...接受[%s][%d]!\n", argv[0], rowid);
fclose(fp);
}
sigset(SIGCLD, mysig);
/* 子进程启动相应程序,父进程等待 */
if (fork()==0)
execve(argv[0], argv, envp);
else pause();
/* 记录退出登录的时间 */
net_logit(lport, ips, rport, k);
return 0;
}
[/code:1:d719df063a]
cxzty 回复于:2005-08-02 00:05:31
|
收下
|
luolh 回复于:2005-08-09 10:22:47
|
我看看 不知道测试情况怎么样?
|
yutian 回复于:2005-08-09 11:08:16
|
收下先,
|
boclif 回复于:2005-08-10 17:13:29
|
程序不错,但实现这个功能好像不用这么麻烦,我记得在系统下配个文件就可以了.
|
ChinaOK 回复于:2005-08-10 18:09:34
|
mark!
|
zhyesno 回复于:2005-08-11 10:55:43
|
先收,看看。。。谢谢。
|
zhkun 回复于:2005-08-11 15:52:34
|
使用shell就可以实现的。不过还是说,不错的。
|
abist 回复于:2005-08-12 20:28:13
|
不错
|
原文转自:http://www.ltesting.net
|