那个充满激情的岁月

那些年,我们一些为了BBS(网上论坛)而疯狂。为此,曾经刷在线时间(类似QQ刷太阳等级),动手在服务器上写了一个程序。作为留念,现决定低调开源。

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <time.h>

#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
//#include <iconv.h>

#define LOCKFILE "/var/run/bbs4gzhu.pid"

#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)


int                 lockfile;                  /* 锁文件的描述字 */
int 		    exit_flag = 0;


#define BUFFER_SIZE	409600
#define FORMHASH_SIZE	16
#define USERNAME_SIZE	128
#define PASSWORD_SIZE	128
#define SID_SIZE	64
#define AUTH_SIZE	128

int		    background = 0;
int 		    interval = 15;
char 		   *cookiepath = "";
char 		   username[USERNAME_SIZE] = "";
char 		   password[PASSWORD_SIZE] = "";
char		   *host = "bbs.gzhu.edu.cn";
short 		   port = 80;


static void
flock_reg ()
{
    char buf[16];
    struct flock fl;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    fl.l_type = F_WRLCK;
    fl.l_pid = getpid();
 
    //阻塞式的加锁
    if (fcntl (lockfile, F_SETLKW, &fl) < 0){
        perror ("fcntl_reg");
        exit(EXIT_FAILURE);
    }
 
    //把pid写入锁文件
    ftruncate (lockfile, 0);    
    sprintf (buf, "%ld", (long)getpid());
    write (lockfile, buf, strlen(buf) + 1);
}

void
daemon_init(void)
{
	pid_t	pid;
    	int     fd0;

	if ( (pid = fork()) < 0)
	    perror ("Fork");
	else if (pid != 0) {
        	fprintf(stdout, "bbs4gzhu&&Info: Forked background with PID: [%d]\n\n", pid);
		exit(EXIT_SUCCESS);
    	}
	setsid();	/* become session leader */
	chdir("/tmp");		/* change working directory */
	umask(0);		/* clear our file mode creation mask */
    flock_reg ();

    fd0 = open ("/dev/null", O_RDWR);
    dup2 (fd0, STDIN_FILENO);
    dup2 (fd0, STDERR_FILENO);
    dup2 (fd0, STDOUT_FILENO);
    close (fd0);
}


static int 
is_running()
{
    struct flock fl;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    fl.l_type = F_WRLCK;
 
    //尝试获得文件锁
    if (fcntl (lockfile, F_GETLK, &fl) < 0){
        perror ("fcntl_get");
        exit(EXIT_FAILURE);
    }

    if (exit_flag) {
        if (fl.l_type != F_UNLCK) {
            if ( kill (fl.l_pid, SIGINT) == -1 )
            perror("kill");
            fprintf (stdout, "bbs4gzhu&&Info: Kill Signal Sent to PID %d.\n", fl.l_pid);
        }
        else 
            fprintf (stderr, "bbs4gzhu&&Info: Program not running.\n");
        exit (EXIT_FAILURE);
    }


    //没有锁,则给文件加锁,否则返回锁着文件的进程pid
    if (fl.l_type == F_UNLCK) {
        flock_reg ();
        return 0;
    }

    return fl.l_pid;
}
static void
signal_interrupted (int signo)
{
    exit (EXIT_SUCCESS);
    exit_flag = 1;
    fprintf(stdout,"\nbbs4gzhu&&Info: Interrupted. \n");
}
static void show_usage()
{
	printf("auto online for bbs.gzhu.edu.cn \n\
options: \n \
	-b --background. run in background. mostly this is for service mode. \n\
	-e --exit. quit the running program in background \n\
	-i --interval value(in second). interval time between online request. default value is 15 seconds. \n\
	-h --help. show this usage message. \n\
	-c --cookiepath. specifies the file containing the cookies for online request. \n\
	-u --username. username for login in the bbs. \n\
	-p --password. md5 of the password, used for login in the bbs. \n\
	--host. host for auto online. default value is \"bbs.gzhu.edu.cn\" \n\
	--port. the port with site. default value is 80. \n");


}

static void 
init_arguments(int *argc, char ***argv)
{
    /* Option struct for progrm run arguments */
    static struct option long_options[] =
        {
        {"background",  no_argument,        &background,    'b'},       
        {"exit",      no_argument,  &exit_flag,              'e'},
        {"interval",         required_argument,  &interval,              'i'},
        {"help",         no_argument,  0,              'h'},
        {"cookiepath",         required_argument,  NULL,              'c'},
	{"username", required_argument, NULL, 'u'},
	{"password", required_argument, NULL, 'p'},
	{"host", required_argument, NULL, 2},
	{"port", required_argument, NULL, 1},
        {0, 0, 0, 0}
        };

    int c;
    while (1) {

        /* getopt_long stores the option index here. */
        int option_index = 0;
        c = getopt_long ((*argc), (*argv), "bei:hc:u:p:",
                        long_options, &option_index);
        if (c == -1)
            break;
        switch (c) {
            case 0:
               break;
            case 'b':
                background = 1;
                break;
            case 'e':
                exit_flag = 1;
                break;
	    case 'i':
                interval = atoi(optarg);
                break;
            case 'h':
                show_usage();
                exit(EXIT_SUCCESS);
                break;
	    case 'c':
		cookiepath = optarg;
		break;
	    case 'u':
		strncpy(username, optarg, USERNAME_SIZE);
		break;
	    case 'p':
		strncpy(password, optarg, PASSWORD_SIZE);
		break;
	    case 2:
		host = optarg;
		break;
	    case 1:
		port = atoi(optarg);
		break;
            case '?':               
                exit(EXIT_FAILURE);
                break;
            default:
                fprintf (stderr,"Unknown option character `\\x%x'.\n", c);
                exit(EXIT_FAILURE);
        }
    }
}

void PANIC(char *msg);
#define PANIC(msg)  {perror(msg); abort();}
int getitem(const char *str, char *buffer, const int size, const char *start, const char end);

int tcp_connect(const char *host, const short port);
struct sockaddr_in getaddr(const char *host, const short port);
void loadcookies(const char *filename, char *buffer, const int size);
int 
code_convert(char *from_charset, char *to_charset,
             char *inbuf, size_t inlen, char *outbuf, size_t outlen);

int parse_username(const char *str, char *buffer, const int size);
int parse_formhash(const char *str, char *buffer, const int size);
int parse_sid(const char *str, char *buffer, const int size);
int parse_auth(const char *str, char *buffer, const int size);
int parse_parse_cookies(const char *str, char *buffer, const int size);
int parse_welcome_msg(const char *str, char *buffer, const int size);
int parse_return_msg(const char *str, char *buffer, const int size);
int parse_error_msg(const char *str, char *buffer, const int size);

int login(const char *username, const char *password, char *cookies, const int size);
int send_request(const int sockfd, const char *url, const char *header, const char *data, char *buffer, const int size);
int check_http(const char *response, const int size);
int online(const char *cookies);
char *gettime();

int
main(int argc, char *argv[])
{
	int ins_pid;
	char cookies[BUFFER_SIZE];

	init_arguments(&argc, &argv);

	lockfile = open (LOCKFILE, O_RDWR | O_CREAT , LOCKMODE);
	if (lockfile < 0){
		perror ("Lockfile");
		exit(EXIT_FAILURE);
	}

	if ( (ins_pid = is_running()) ) {
		fprintf(stderr,"bbs4gzhu@@ERROR: Program already "
				    "running with PID %d\n", ins_pid);
		exit(EXIT_SUCCESS);
	}

	signal (SIGINT, signal_interrupted);
	signal (SIGTERM, signal_interrupted);

	bzero(cookies, sizeof(cookies));
	if(strlen(cookiepath) > 0) {
		loadcookies(cookiepath, cookies, sizeof(cookies));
		if(strlen(username) <= 0) {
			if(parse_username(cookies, username, sizeof(username)) <= 0) {
				if(parse_sid(cookies, username, sizeof(username)) <= 0) {
					strcpy(username, "unknown");
				}
			}
		}
	} else {
		if(strlen(username) <= 0) {
			strcpy(username, "nobody");
		}
	}

	printf("current username: %s \n", username);

	if(background)    daemon_init();

	while(1) {
		printf("%s logging...", gettime());
		fflush(stdout);
		if(!login(username, password, cookies, sizeof(cookies))) {
			sleep(interval);
			continue;
		}
		printf("\n");
		while(online(cookies)) {
			printf("%s online...\r", gettime()); fflush(stdout);
			sleep(interval);
		}
		printf("%s offline...it will auto retrying!\n", gettime());
	}

	return 0;
}/* ----------  end of function main  ---------- */
char *gettime()
{
	static char str[64];
	struct tm *local;
	time_t t;
	t = time(NULL);
	local=localtime(&t);
	sprintf(str, "%02d:%02d:%02d", local->tm_hour, local->tm_min, local->tm_sec);
	return str;
}
int check_http(const char *response, const int size)
{
	char buffer[16];
	if(size <= 16) return 0;
	if(strstr(response, "HTTP/1.1 200 OK\r\n") == NULL) {
		strncpy(buffer, response, 15);
		buffer[15] = 0;
		printf("%s bad status:%s\n", username, buffer);
		return 0;
	}
	return 1;
}

void loadcookies(const char *filename, char *buffer, const int size)
{
	int bytes_read;
	FILE *fd = fopen(filename, "r");
	if(fd == NULL) {
		PANIC("loadcookies");
	}
	bytes_read = fread(buffer, 1, size, fd);
	buffer[bytes_read - 1] = 0;
	
	while(bytes_read--) {
		if(buffer[bytes_read] == '\r') buffer[bytes_read] = ' ';
		if(buffer[bytes_read] == '\n') buffer[bytes_read] = ' ';
	}
	
	fclose(fd);
}

int send_request(const int sockfd, const char *url, const char *header, const char *data, char *buffer, const int size) 
{
	int bytes_read = 0;
	char request_buffer[BUFFER_SIZE];
	if(data != NULL) {
		sprintf(request_buffer, "POST %s HTTP/1.1\r\nHost: %s:%d\r\nReferer: http://%s\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n%s\r\n\r\n%s", url, host, port, host, strlen(data), header, data);
	} else {
		sprintf(request_buffer, "GET %s HTTP/1.1\r\nHost: %s:%d\r\nReferer: http://%s\r\n%s\r\n", url, host, port, host, header);
	}

	//printf("%s\n", request_buffer);

	/* 发送数据 */
	send(sockfd, request_buffer, strlen(request_buffer), 0);

	/* 接收缓存 */
	bzero(buffer, sizeof(size));

	/* 接收 */
	bytes_read = recv(sockfd, buffer, size, 0);

	//printf("%s\n", buffer);

	return bytes_read;
}

int login(const char *username, const char *password, char *cookies, const int size) 
{
	int sockfd;
	int bytes_read;
	char buffer[BUFFER_SIZE];
	char header[BUFFER_SIZE];
	char formhash[FORMHASH_SIZE];
	char formdata[BUFFER_SIZE];
	char sid[SID_SIZE];
	char auth[AUTH_SIZE];
	char msg[BUFFER_SIZE];

	/* 先获取登录页面 */
	sockfd = tcp_connect(host, port);
	bytes_read = send_request(sockfd, "/logging.php?action=login&inajax=1", "", NULL, buffer, sizeof(buffer));	
	close(sockfd);
	if(check_http(buffer, bytes_read) == 0) return 0;
//	printf("%s\n", buffer);
	
	/* 若被列入黑名单,则等待3分钟后再试 */
	if(strlen(strstr(buffer, "\r\n\r\n")+4) <= 120) {//这个值一般在99左右。
		bytes_read = parse_error_msg(buffer, msg, sizeof(msg));
		if(bytes_read > 0 && strstr(msg, "\n") == NULL) {
			printf("Error:%s . Try 15m later..\r", msg);	
		} else {
			printf("Error:unknown. Try 3 minute later..\r", msg);
		}
		fflush(stdout);
		sleep(3*60);
		return 0;
	}
	/* 解析formhash */
	bytes_read = parse_formhash(buffer, formhash, sizeof(formhash));
	if(bytes_read <= 0) return 0;

	/* 解析SID */
	bytes_read = parse_sid(buffer, sid, sizeof(sid));
	if(bytes_read <= 0) return 0;

	strcat(cookies, "hLR_sid=");	strcat(cookies, sid);	strcat(cookies, ";");

	/* 构造header */
	sprintf(header, "Cookie: %s\r\n", cookies);

	/* 构造登录表单 */
	sprintf(formdata, "formhash=%s&loginfield=username&username=%s&password=%s&questionid=0&answer=&cookietime=2592000", formhash, username, password);

//	printf("%s %s\n", header, formdata);
	
	/* 提交登录请求 */
	sockfd = tcp_connect(host, port);
	bytes_read = send_request(sockfd, "/logging.php?action=login&loginsubmit=yes&inajax=1", header, formdata, buffer, sizeof(buffer));
	close(sockfd);
	if(check_http(buffer, bytes_read) == 0) return 0;

	/* 解析欢迎消息 */
	bytes_read = parse_welcome_msg(buffer, msg, sizeof(msg));
	if(bytes_read <= 0)  {
		/* 解析登录返回信息 */
		bytes_read = parse_return_msg(buffer, msg, sizeof(msg));
		if(bytes_read > 0) printf("Failed Info:%s\r", msg);
		return 0;
	}
	printf("Login Info:%s\r", msg);
	fflush(stdout);

	/* 解析auth */
	bytes_read = parse_auth(buffer, auth, sizeof(auth));
	if(bytes_read <= 0) return 0;	
	strcat(cookies, "hLR_auth=");	strcat(cookies, auth);	strcat(cookies, ";");

	/* 有效时间 */
	strcat(cookies, "hLR_cookietime=2592000;");

	return strlen(cookies);
}

int online(const char *cookies)
{
	int sockfd;
	int bytes_read;
	char buffer[BUFFER_SIZE];
	char header[BUFFER_SIZE];

	/* 构造header */
	sprintf(header, "Cookie: %s\r\n", cookies);

	/* 刷新页面保持在线 */
	sockfd = tcp_connect(host, port);
	bytes_read = send_request(sockfd, "/search.php", header, NULL, buffer, sizeof(buffer));	
	close(sockfd);
	if(check_http(buffer, bytes_read) == 0) return 0;
	
	/* 检测用户凭据是否到期 */
	if(strstr(buffer, "logging.php?action=logout") == NULL) return 0;

	return 1;
}

int parse_error_msg(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "![CDATA[", ']');
}

int parse_username(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "uchome_loginuser=", ';');
}

int parse_formhash(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "name=\"formhash\" value=\"", '\"');
}

int parse_sid(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "hLR_sid=", ';');
}

int parse_auth(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "hLR_auth=", ';');
}

int parse_cookies(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "Set-Cookie: ", ';');	
}

int parse_welcome_msg(const char *str, char *buffer, const int size)
{
	return getitem(str, buffer, size, "$('messageleft').innerHTML = '", '\'');	
}


int parse_return_msg(const char *str, char *buffer, const int size)
{
	return getitem(str, buffer, size, "<em id=\"returnmessage\">", '<');	
}


int getitem(const char *str, char *buffer, const int size, const char *start, const char end)
{
	int i;
	char *p = strstr(str, start);
	if(p == NULL) return 0;

	for(i = 0, p+= strlen(start); p[i] &&  i < (size - 1); i++) {
		if(p[i] == end) break;
		buffer[i] = p[i];
	}
	buffer[i] = '\0';
	return i;
}



struct sockaddr_in getaddr(const char *host, const short port)
{
    struct sockaddr_in sin;
    struct hostent *hosts = NULL;

    bzero(&sin, sizeof(struct sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    if(inet_addr(host) == INADDR_NONE) {
        hosts = gethostbyname(host);
	if(hosts != NULL) {
	    sin.sin_addr = *((struct in_addr*)hosts->h_addr);
	}
    } else {
	sin.sin_addr.s_addr = inet_addr(host);
    }
    return sin;
}

int
tcp_connect(const char *host, const short port)
{

    int     sockfd;
    struct sockaddr_in endpoint;

    endpoint = getaddr(host, port);
  
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) return 0;

    if (connect(sockfd, (struct sockaddr*)&endpoint, sizeof(struct sockaddr_in)) != 0) {
	close(sockfd); 
	return 0;
    }

    return (sockfd);
}

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  code_convert
 *  Description:  字符串编码转换
 * =====================================================================================
 */
int 
code_convert(char *from_charset, char *to_charset,
             char *inbuf, size_t inlen, char *outbuf, size_t outlen)
{
    memcpy(outbuf, inbuf, inlen < outlen ? inlen : outlen);
/*
    iconv_t cd;

    cd = iconv_open(to_charset,from_charset);

    if (cd==0) 
      return -1;
    memset(outbuf,0,outlen);

    if (iconv (cd, &inbuf, &inlen, &outbuf, &outlen)==-1) 
      return -1;
    iconv_close(cd);
*/
    return 0;
}


一个合并bib文件的小工具

因为当写过两篇文章之后,偶尔来个汇报之类的,就需要将之前文章的参考文献汇集在一起处理。然而这些文献本身可能是大量重复的,如何将多个bib文件中的重复文献去掉,仅保留不重复的部分,并最终输出到一个合并之后的bib文件中,是写这个小工具的一个背景。

原来的bib文件已经有自己的citation key,而且自己也习惯于这样的生成方式。虽然有一些文献管理软件也有此功能,但有如下弊端:

1)基于title来去重,而不是citation key去重;
2)bib文件中的其他非文献信息会被清除掉;
3)导出后原来的citation key无法保持原样

考虑到以上因素,所以就写了这个小工具:https://github.com/tpu01yzx/BibtexParser

这个工具的用法很简单,主要是几个参数:

1) -O –output 设置合并后输出到的文件名,缺省是标准输出设备。
2) –onlyregular 是否只输出Reguler(类似article,book,misc之类表示具体的文献记录,而非辅助信息如comment, string)的记录,默认为否。
3) –outputplain 是否输出非@开头的记录,这类块大部分是注释或者用于格式控制的,默认为否。

当然了,仅有这个工具,用起来还是有点麻烦,所以最后送上一个Bat批处理文件,把这个批处理文件,bib合并小工具,以及要合并的所有bib文件放在同一个目录。执行这个批处理文件,就不用每次都去找命令行,对于大部分习惯了Windows的用户来说应该是件好事。

@echo off
SetLocal EnableDelayedExpansion

set allbib=_all.bib
set exec=bib_combiner.exe

echo @comment{this file is generated by BibtexParser.exe} > %allbib%
set list=
for  %%i in (*.bib) do ( 
	if not "%%i" == "%allbib%" (		
		set list=!list! "%%i"
	)
)
%exec% "%allbib%" %list% -O "%allbib%" -R
%exec% --help
set exec=
set allbib=
set list=
pause

给伸手党准备好了,Windows下的打包(包含上面提到的一个工具和一个批处理文件:bib_combiner.exe和一个run.bat),点击这里下载

一种二元序列的线性复杂度算法的实现

#include <stdio.h>
#include <memory.h>

#define MAXL (1000)

typedef unsigned char uchar;

void prints(const uchar *s, const int n)
{
    int i;
    for(i=0;i<n;i++) {printf("%u",s[i]);}
    printf("\n");
}

//implement the Berlekamp–Massey algorithm for binary sequences.
//Please see https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm#The_algorithm_for_the_binary_field
int bm(const uchar*s, const int n)
{
    int i,j,lc,m,d;
    uchar b[MAXL];
    uchar c[MAXL];
    uchar t[MAXL];
    
    b[0]=1;c[0]=1;
    for(i=1;i<n;i++){b[i]=0;c[i]=0;};
  
    lc=0;m=-1;
    
    for(i=0;i<n;i++) {
        d=s[i];
        for(j=1;j<=lc;j++) { d ^=s[i-j] & c[j]; }
        if(d!=0){
            memcpy(t,c,n);
            for(j=0;j<n-i+m;j++) { c[i-m+j]^=b[j]; }
            
            if(2*lc<=i) {
                lc=i+1-lc;
                m=i;
                memcpy(b,t,n);
            }
        }
    }
  
    return lc;
}

int main()
{
    int n;
    int lc;
    char c;
    int i,j;
    uchar s[MAXL];
    uchar ans_s[MAXL];
    int ans_lc;
    int ans_j;
    
    //if you would like to read the sequence from file, please uncomment the follows line.
    //freopen ("s1.txt","r",stdin);
    //skip the first line
    while((c=getchar())!='\n');
    //read the sequence
    n=0;
    while(n<MAXL){
        c=getchar();
        //the line should be ended with '\n' or ']'.
        if(c=='\n' || c==']') break;
        
        //only '0' and '1' are captured.
        if(c>='0' && c<='1') {
            //convert '0' and '1' to 0 and 1.
            s[n++]=c-'0';
        }
    }
    prints(s,n);
    printf("There are %d bits.\n", n);
    
    lc = bm(s,n);
    printf("The original LC is %d\n", lc);
    
    //make sure that current ans_lc is big enough.
    ans_lc=n; ans_j=-1;
    for(i=0;i<n;i++) {
        s[i] ^=1;
        
        lc=bm(s,n);
        if(lc<ans_lc) {
            //save the current optimal answer;
            ans_lc=lc; ans_j=i;
            memcpy(ans_s,s,n);
            printf("Update ans with lc=%d when  s[%u]:%u->%u.\n", 
            ans_lc, ans_j, s[ans_j]^1, ans_s[ans_j]);
        }
        
        s[i] ^=1;
    }
    
    printf("The minimal 1+lc is %d when s[%u]:%u->%u.\n", 
        1+ans_lc, ans_j, s[ans_j], ans_s[ans_j]);
    prints(ans_s,n);
    
    
    return 0;
}

这是基于C语言实现的wiki上二元序列的线性复杂度,如果需要对应的极小多项式可以从最后的c变量数组中直接转换过来,这并不是什么有难度的事情。

VPN拨号后自动处理路由策略(For Windows)

经常使用各种不同的VPN,但一般客户端都需要根据不同的场景来选择配置不同的路由策略,很久之前写过一个批处理脚本(For Win)。今天突然要用,但是找不到了,所以只好重新再写一次,然后保存下来,希望下次会记得。

PS:Linux类系统下自然有更多优秀的解决方案,或者说第三方VPN插件自然也会很优雅的解决办法,自然不必纠结我这个批处理的脚本,只给有需要的人。

@echo off
Setlocal enabledelayedexpansion
rem 校内常见的私有地址,例如教务系统,OA办公系统等
set ip0=10.0.0.0/8;
set prefix=10.0.0.
rem =====================以上部分不要修改===========================================

rem 所有需要通过VPN访问的IP,用分号隔开。支持添加整个子网。最多添加到ip3,并且每个都要以分号结尾
set ip1=211.155.94.138;122.115.55.6;
set ip2=
set ip3=

rem 用户名user
set user=XXX

rem 密码pass
set pass=XXX

rem 新建vpn连接的名称,可以在"控制面板"的"网络连接"中看到
set vpn_name=gdst

rem =====================以下部分不要修改=================================
set ip4=172.16.0.0/16
set ipt="%ip0% %ip1% %ip2% %ip3% %ip4%"
set "ips=%ipt: =%"
set try=0
set mask=
set aip=
set ans=
set ip=

:dial
cls
echo 正在VPN连接...
rasdial %vpn_name% %user% %pass%
if errorlevel 1 (
set /a try+=1
echo 第%try%次拨号失败,5秒后重新尝试,按Ctrl+C终止
ping 1.1.1.1 -n 1 -w 5000 > nul
goto dial
) else (
echo 拨号成功.
)
rem VPN获取的IP地址应该是10.0.0开头的

for /f "tokens=1* delims=:" %%i in ('ipconfig /all^|find "%prefix%"') do (
if /i not "%%j" == "" (
set ip=%%j
goto ipout
)
)
:ipout
echo VPN的IP地址为:%ip%
echo 正在处理网络配置,如果失败,请修复本地连接后重新尝试。
rem 删除拨号成功后默认添加的路由
rem route delete 0.0.0.0 mask 0.0.0.0 %ip% METRIC 1 >NUL 2>NUL
call:clean
call:add_all %ips%
echo 网络配置完毕。

:menu
rem cls
rem echo 当前路由表为(仅供调试之用)
rem route print %prefix%
set /p user_input=输入1,将自动断开vpn,并恢复原来的网络配置。
if /i not "%user_input%"=="1" goto menu

rasdial %vpn_name% /DISCONNECT
call:clean
echo 操作完毕,请关闭此窗口。
pause
exit

:gmask
set /a nid=32
set /a q=4
set /a r=0
set aip=%~1
set "aip=%aip: =%"
if "!aip!" == "" goto:eof
for /f "delims=/, tokens=1,*" %%s in ("%~1") do (
if /i not "%%t"=="" (
set /a q="%%t/8"
set /a nid="%%t"
set aip=%%s
)
)

set /a r="%nid%-%q%*8"
if %nid% GEQ 32 (
set mask=255.255.255.255.
) else if %nid% LEQ 0 (
set mask=0.0.0.0.
) else (
set mask=
for /L %%i in (1,1,%q%) do (
set mask=!mask!255.
)
set /a next="%q%+1"
if %r% GTR 0 (
set /a smask=1"<<"%r% set /a smask=256-!smask! set mask=!mask!!smask!. ) for /L %%i in (!next!,1,4) do ( set mask=!%mask!0. ) ) set "mask=%mask:~0,-1%" goto:eof :add_all for /f "delims=;, tokens=1,*" %%i in ("%~1") do ( call:gmask "%%i" echo 正在处理 %%i !aip! !mask! %ip% if /i not "!aip!" == "" ( route add !aip! mask !mask! %ip% METRIC 1 >NUL 2>NUL
)
if /i not "%%j"=="" (
call:add_all "%%j"
)

)
goto:eof

:clean
for /f "tokens=1-4" %%i in ('route print ^| find "!ip!"') do (
route delete %%i mask %%j !ip! >NUL 2>NUL
)
goto:eof

执行后显示的日志信息如下:

正在VPN连接…
正在连接到 GDST…
正在验证用户名及密码…
正在网络上注册您的计算机…
已连接 GDST。
命令已完成。
拨号成功.
VPN的IP地址为: 10.0.0.4
正在处理网络配置,如果失败,请修复本地连接后重新尝试。
正在处理 10.0.0.0/8 10.0.0.0 255.0.0.0 10.0.0.4
正在处理 211.155.94.138 211.155.94.138 255.255.255.255 10.0.0.4
正在处理 122.115.55.6 122.115.55.6 255.255.255.255 10.0.0.4
正在处理 172.16.0.0/16 172.16.0.0 255.255.0.0 10.0.0.4
网络配置完毕。
输入1,将自动断开vpn,并恢复原来的网络配置。1
命令已完成。
操作完毕,请关闭此窗口。
请按任意键继续. . .

同伴矩阵的方幂

最近在研究一个矩阵的方幂,这个矩阵如下

    \[A=\left( \begin{array}{ccc}  0 & 0 & -a_0 \\  1 & 0 & -a_1 \\  0 & 1 & -a_2 \\ \end{array} \right).\]

事实上这个矩阵和下面这个多项式存在一一对应的关系,

    \[f(x)=x^3+a_2x^2+a_1x+a_0.\]

使用Mathematica计算A^k, 代码如下:
<< FiniteFields` Assuming[Element[p, Primes] && Element[n, Integers] && n > 0,
F = GF[p, n];
A = {{0, 0, -a[0]}, {1, 0, -a[1]}, {0, 1, -a[2]}};
Print[MatrixForm[
Simplify[MatrixPower[A, k],
Element[a[0], F] && Element[a[1], F] && Element[a[2], F] &&
Element[k, Integers] && k > 1]]];
];

计算结果为:

    \[\left( \begin{array}{ccc}  \frac{x_2 x_3 x_1^k}{\left(x_1-x_2\right) \left(x_1-x_3\right)}+\left(\frac{x_3 x_2^k}{x_2^2-a_1+2 x_1 x_3}+\frac{x_3^k x_2}{\left(x_1-x_3\right) \left(x_2-x_3\right)}\right) x_1 & a_0 \left(\frac{x_2^k}{-x_2^2+a_1-2 x_1 x_3}+\frac{\frac{x_3^k}{x_3-x_2}-\frac{x_1^k}{x_1-x_2}}{x_1-x_3}\right) & a_0 \left(\frac{\left(a_2+x_2+x_3\right) x_1^k}{\left(x_1-x_2\right) \left(x_1-x_3\right)}+\frac{x_3^{k+1}}{\left(x_1-x_3\right) \left(x_3-x_2\right)}+\frac{x_2^{k+1}}{-x_2^2+a_1-2 x_1 x_3}\right) \\  \frac{x_1 x_2 x_3 \left(-\frac{\left(a_2+x_1\right) x_1^k}{\left(x_1-x_2\right) \left(x_1-x_3\right)}+\frac{x_3^k \left(a_2+x_3\right)}{\left(x_1-x_3\right) \left(x_3-x_2\right)}+\frac{x_2^k \left(a_2+x_2\right)}{-x_2^2+a_1-2 x_1 x_3}\right)}{a_0} & \frac{\left(a_2+x_1\right) x_1^{k+1}}{\left(x_1-x_2\right) \left(x_1-x_3\right)}+\frac{x_3^{k+1} \left(a_2+x_3\right)}{\left(x_3-x_1\right) \left(x_3-x_2\right)}+\frac{x_2^{k+1} \left(a_2+x_2\right)}{x_2^2-a_1+2 x_1 x_3} & -\frac{\left(a_2+x_1\right) \left(a_2+x_2+x_3\right) x_1^{k+1}}{\left(x_1-x_2\right) \left(x_1-x_3\right)}+\frac{x_3^{k+2} \left(a_2+x_3\right)}{\left(x_1-x_3\right) \left(x_2-x_3\right)}+\frac{x_2^{k+2} \left(a_2+x_2\right)}{x_2^2-a_1+2 x_1 x_3} \\  \frac{-x_1 x_3 \left(x_1^k+x_2^k-2 x_3^k\right) x_2^2+x_1 x_3^2 \left(x_1^k-2 x_2^k+x_3^k\right) x_2+a_0 a_2 \left(x_2^k-x_3^k\right)}{a_0 \left(x_1-x_2\right) \left(x_1-x_3\right) \left(x_2-x_3\right)} & \frac{x_1^{k+1}}{\left(x_1-x_2\right) \left(x_1-x_3\right)}+\frac{x_3^{k+1}}{\left(x_3-x_1\right) \left(x_3-x_2\right)}+\frac{x_2^{k+1}}{x_2^2-a_1+2 x_1 x_3} & -\frac{\left(a_2+x_2+x_3\right) x_1^{k+1}}{\left(x_1-x_2\right) \left(x_1-x_3\right)}+\frac{x_3^{k+2}}{\left(x_1-x_3\right) \left(x_2-x_3\right)}+\frac{x_2^{k+2}}{x_2^2-a_1+2 x_1 x_3} \\ \end{array} \right).\]

显然在化简方面,Mathematica并没有充分利用a_0,a_1,a_2是有限域上的元素的特点,所以这个表达式还是挺复杂的,需要自己进一步做化简. 最终的目标是为了计算det(A^k-I).

突然灵机一动, 改动了一下Mathematica的代码如下:
<< FiniteFields` Assuming[Element[p, Primes] && Element[n, Integers] && n > 0,
F = GF[p, n];
A = {{0, 0, -a[0]}, {1, 0, -a[1]}, {0, 1, -a[2]}};
Print[MatrixForm[
Simplify[Det[MatrixPower[A, k] - IdentityMatrix[3]],
Element[a[0], F] && Element[a[1], F] && Element[a[2], F] &&
Element[k, Integers] && k > 1]]];
];

结果为:

    \[det(A^k-I)=(-1+x_1^k) (-1+x_2^k) (-1+x_3^k),\]

其中x_1,x_2,x_3是方程f(x)的三个根.

[转]中国很多网上银行客户数字证书配置不当

漏洞概要

缺陷编号: WooYun-2012-09482

漏洞标题: 中国很多网上银行客户数字证书配置不当

相关厂商: 中国很多银行&支付宝

漏洞作者: tpu01yzx

提交时间: 2012-07-13 15:14

公开时间: 2012-07-16 01:46

漏洞类型: 默认配置不当

危害等级: 低

自评Rank: 1

漏洞状态: 已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org

Tags标签: 设计不当导致攻击界面扩大 盲目信任用户数据 杀毒绕过 网络资源滥用 证书签发策略错误


漏洞详情

披露状态:

2012-07-13: 细节已通知厂商并且等待厂商处理中
2012-07-13: 厂商已查看当前漏洞内容,细节仅向厂商公开
2012-07-16: 厂商已经主动忽略漏洞,细节向公众公开

简要描述:

就是可以使用网上银行和支付宝签发给用户进行身份验证的数字证书进行代码签名。

会有什么危害呢?看那个“数字签名正常”几个字就知道了。除了可以通过浏览器控件的签名验证之外,还可以逃避一下杀毒软件的查杀(目前很多杀软都是忽略“可信任”的软件白名单)

详细说明:

第一张使用的是农业银行发布的数字证书做的code签名

第二张使用的是支付宝发布的数字证书做的code签名

他们对应的根证书自己到官网下载安装,不解释。至于如何做code签名,微软有个signcode.exe,也不解释了。

会有什么危害呢?看那个“数字签名正常”几个字就知道了。除了可以通过浏览器控件的签名验证之外,还可以逃避一下杀毒软件的查杀(目前很多杀软都是忽略“可信任”的软件白名单)

漏洞证明:

第一张使用的是农业银行发布的数字证书做的code签名

第二张使用的是支付宝发布的数字证书做的code签名

修复方案:

别自以为是地自己给自己签名做CA,买个第三方认证的证书不需要花多少钱吧。怕国外的不安全,国内的也有权威的数字认证机构啊,不解释。

或者

给用户签发数字证书的时候,那个“证书的目的”控制一下,比如说:

客户端验证

安全电子邮件

智能卡登录

而不要用默认那个”所有应用程序策略”,不解释哈。

版权声明:转载请注明来源 tpu01yzx@乌云


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2012-07-16 01:46

厂商回复:

参考评论,对于此类问题暂不进行处置。

漏洞Rank:13 (WooYun评价)

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

[转]腾讯将乌云列入黑名单

漏洞概要

缺陷编号: WooYun-2011-03899

漏洞标题: 腾讯将乌云列入黑名单

相关厂商: 腾讯

漏洞作者: tpu01yzx

提交时间: 2011-12-29 15:52

公开时间: 2012-01-03 15:53

漏洞类型: 设计错误/逻辑缺陷

危害等级: 低

自评Rank: 5

漏洞状态: 漏洞已经通知厂商但是厂商忽略漏洞

漏洞来源: http://www.wooyun.org

Tags标签: 潜规则


漏洞详情

披露状态:

2011-12-29: 细节已通知厂商并且等待厂商处理中
2011-12-29: 厂商已查看当前漏洞内容,细节仅向厂商公开
2012-01-03: 厂商已经主动忽略漏洞,细节向公众公开

简要描述:

腾讯将乌云列入黑名单,导致用户无法及时获得最新的漏洞信息。
<img src=”/upload/201112/29155031c26f97276a1628875e231bd9ad07b4ef.jpg” />

详细说明:

看图,不解释。

漏洞证明:

看图,不解释。

修复方案:

你懂的。

版权声明:转载请注明来源 tpu01yzx@乌云


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2012-01-03 15:53

厂商回复:

漏洞Rank:3 (WooYun评价)

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

[转]QQ被迫下线后未使会话令牌失效

漏洞概要

缺陷编号: WooYun-2011-03679

漏洞标题: QQ被迫下线后未使会话令牌失效

相关厂商: 腾讯

漏洞作者: tpu01yzx

提交时间: 2011-12-20 09:31

公开时间: 2012-02-03 09:32

漏洞类型: 非授权访问/认证绕过

危害等级: 低

自评Rank: 1

漏洞状态: 厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 help@wooyun.org

Tags标签: 认证设计不合理 腾讯认证 认证绕过 用户认证信息泄漏 认证系统设计不合理 认证信息不同步


漏洞详情

披露状态:

2011-12-20: 细节已通知厂商并且等待厂商处理中
2011-12-20: 厂商已经确认,细节仅向厂商公开
2011-12-23: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2012-02-13: 细节向核心白帽子及相关领域专家公开
2012-02-23: 细节向普通白帽子公开
2012-03-04: 细节向实习白帽子公开
2012-02-03: 细节向公众公开

简要描述:

很简单,就是一个地方登陆了QQ,另一个地方再登陆的时候就会导致前面的登陆出现被迫下线的情况。但此时,虽然客户端的QQ是离线状态,但是通过点击QQ客户端控制面板上的按钮还是可以正常访问QQ空间,QQ邮箱等信息。这个和那种会话劫持的原理很类似。
于是有如下猜想:只有一次登陆成功,记录下会话信息,即使之后执行退出操作,仍可以使用之前的会话信息通过认证。

详细说明:

按照问题描述操作一次。

漏洞证明:

省略。

修复方案:

你懂的。

版权声明:转载请注明来源 tpu01yzx@乌云


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:1

确认时间:2011-12-20 11:14

厂商回复:

thanks

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值