COMMENTS

  • james@rounter: Hey okay thx. :)
  • james@router: Does my mac adresse change if I upgrade my computer with some...
  • Firm: 这方面没接触过 8-O
  • ontogma: итак: восхитительно… Киев лучшие секс знакомства...
  • 一路阳光: 现在再看刚毕业时的简历肯定感觉有点心虚,当年要不是初生牛犊估 计也没有那份胆量写那样的简历了
  • licream: 我也离了。0 0。不过还没找上。郁闷哦
  • Firm: 公司面试都喜欢考链表 确实,俺上次也考这个了
  • bokit: 今天第一天开工,祝心想事成,顺顺利利 PS:恭喜博主,新的一年新的开始。

使用原始套接字SOCK_RAW捕捉网络数据包并简单分析

协议的分析需要参考前一篇文章以太网帧格式,IP包头,TCP头格式说明。

抓取网络上的数据包需要设置网卡为混杂模式,调用recvfrom在创建的SOCK_RAW类型的socket上接收来自kernel的信息,然后再按照帧格式,IP头,TCP头格式,指针移动到相应位置并分析。

附上的小程序由于其他原因还在UDP9001端口监听了来自客户端的消息,这与本文无关。

?Download zhao_sock.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
#include <stdio.h>  //for printf
#include <stdlib.h> //for exit
#include <string.h> // for strcmp
#include <sys/socket.h> //for socket,address
#include <sys/types.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <sys/ioctl.h> //for ioctl
#include <pthread.h>
 
#define INTERFACE "eth0"
#define BUFFLEN 2048
#define UDPPORT 9001
#define REQUEST 0
#define RESPONSE 1
#define RESERVE 2 
#define z_print(fmt,args...) \
 printf("[%s %d]"fmt"\n",__FILE__,__LINE__,##args)
typedef struct {
 uint8_t version;
 uint8_t type;
 uint8_t len;
 uint16_t number;
 char data[255];
} datasend;
 
void* ch_hanlder();
uint8_t randvalue();
?Download zhao_sock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include "zhao_sock.h"
 
int main(int argc,char *argv[])
{
	int sockfd;
	int len;
	int proto;
	int port_s;
	int port_d;
	char recvbuff[BUFFLEN];
	unsigned char type[4];
	unsigned char *ethhead = NULL;
	unsigned char *iphead = NULL;
	unsigned char *p = NULL;
	struct ifreq ifr;
	pthread_t thread_ch;
 
	pthread_create(&thread_ch,NULL,&ch_hanlder,NULL);
 
	sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL)); 
	if (sockfd < 0)
	{ 
		z_print("socket create error");
		exit(1);
	}
	strcpy(ifr.ifr_name,INTERFACE);
	if (ioctl(sockfd,SIOCGIFFLAGS,&ifr) == -1)
	{
		z_print("set PROMISC fail!\n");
		exit(1);
	}
	ifr.ifr_flags |= IFF_PROMISC;
	if (ioctl(sockfd,SIOCGIFFLAGS,&ifr) == -1)
	{
		z_print("set PROMISC fail!");
		exit(1);
	}
	while(1) 
	{
		len = recvfrom(sockfd,recvbuff,sizeof(recvbuff),0,NULL,NULL);
		if (len < 42)
		{
			z_print("receive error!");
			continue;
		}
		ethhead = recvbuff;  //frame head point
		p = ethhead;
		sprintf(type,"%02x%02x",p[12],p[13]);  //frame type
		if (strcmp(type,"0800") != 0)  //0800 is IP frame
		{
			if (strcmp(type,"0806") == 0)
				printf("protocol: ARP\n");
			else if (strcmp(type,"8035") == 0)
				printf("protocol: RARP\n");
			else
				printf("protocol: unknow\n");
			printf("MAC:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x==>%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n\n", \
				p[6],p[7],p[8],p[9],p[10],p[11],p[0],p[1],p[2],p[3],p[4],p[5]);  //mac address
			continue;
		}
		iphead = ethhead + 14;  //ip head point
		p = iphead + 12; //ip address
		printf("IP:%d.%d.%d.%d==>%d.%d.%d.%d\n", \
			p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
		proto = (iphead + 9)[0];  //ip protocol
		p = iphead + 20; //ip port 
		switch(proto)
		{
			case IPPROTO_ICMP:
			printf("protocol: ICMP\n");
			break;
			case IPPROTO_IGMP:
			printf("protocol: IGMP\n");
			break;
			case IPPROTO_IPIP:
			printf("protocol: IPIP\n");
			break;
			case IPPROTO_TCP:
			case IPPROTO_UDP:
			printf("protocol: %s\n",(proto == IPPROTO_TCP) ? "TCP":"UDP");
			port_s = (p[0]<<8)&0XFF00 | p[1]&0XFF;  //source port
			port_d = (p[2]<<8)&0XFF00 | p[3]&0XFF;  // dest port
			printf("source port:%u,",port_s);
			printf("dest port:%u\n",port_d);
			if (port_s == 80 || port_d == 80)
				printf("protocol: HTTP\n");
			else if (port_s == 67 || port_d == 67)
				printf("protocol: DHCP\n");
			else if (port_s == 21 || port_d == 21)
				printf("protocol: FTP\n");
			else if (port_s == 23 || port_d == 23)
				printf("protocol: TELNET\n");
			else if (port_s == 53 || port_d == 53)
				printf("protocol: DNS\n");
			else if (port_s == 137 || port_d == 137 || port_s == 138 || port_d == 138)
				printf("protocol: NetBIOS/SMB\n");
			else
				printf("protocol: other\n");
			break;
			case IPPROTO_RAW:
			printf("RAW\n");
			break;
			default:
			printf("protocol:unknow(%d)\n",proto);
		}
		printf("\n");
	}	
}
 
void* ch_hanlder()
{
	int sockfd;
	int len;
	int flag_close = 0;
	socklen_t addrlen;
	datasend msg_send;
	datasend msg_recv;
	struct sockaddr_in servaddr;
 
	memset(&msg_send,0,sizeof(datasend));
	memset(&msg_recv,0,sizeof(datasend));
	bzero(&servaddr, sizeof(servaddr));
 
	msg_send.version = 1;
	msg_send.type = RESPONSE;
	sprintf(msg_send.data,"%s","received!");
 
	sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
 
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(UDPPORT);
 
	addrlen = sizeof(struct sockaddr_in);
	if (bind(sockfd, (struct sockaddr *)&servaddr, addrlen) == -1)
	{
		perror("bind error");
		exit(1);
	}
	while (1)
	{
		len = recvfrom(sockfd, &msg_recv, sizeof(datasend),0,(struct sockaddr*)&servaddr, &addrlen);
		printf("version:%3d\n",msg_recv.version);
		printf("type:%d\n",msg_recv.type);
		printf("len:%d\n",msg_recv.len);
		printf("number:%d\n",msg_recv.number);
		printf("data:%s\n",msg_recv.data);
		if (strcmp(msg_recv.data,"close") == 0)
		{
			sprintf(msg_send.data,"%s","close");
			flag_close = 1;
		}
		msg_send.number = msg_recv.number + 1;
		msg_send.len = randvalue();
		sendto(sockfd,&msg_send,sizeof(datasend),0,(struct sockaddr*)&servaddr,addrlen);
		if (flag_close)
			break;
	}
	return;
}
 
uint8_t randvalue()
{
	srand(time(0));
	return (rand() % 255);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "zhao_sock.h"
 
int main(int argc, char *argv[])
{
	int sockfd;
	int len;
	socklen_t addrlen;
	struct sockaddr_in cliaddr;
	FILE *fd;
	datasend msg_send;
	datasend msg_recv;
 
	fd = fopen("/root/zhao_log.txt","a");
	memset(&msg_send,0,sizeof(datasend));
	memset(&msg_recv,0,sizeof(datasend));
	bzero(&cliaddr, sizeof(cliaddr));
 
	msg_send.version = 1;
	msg_send.type = REQUEST;
	msg_send.number = 1;
	msg_send.len = randvalue();
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
 
	cliaddr.sin_family = AF_INET;
	cliaddr.sin_port = htons(UDPPORT);
	cliaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
 
	addrlen = sizeof(struct sockaddr_in);
 
	while (1)
	{
	printf("please input send msg:");
	scanf("%s",msg_send.data);
 
	sendto(sockfd,&msg_send,sizeof(datasend),0,(struct sockaddr*)&cliaddr,addrlen);
	len = recvfrom(sockfd, &msg_recv, sizeof(datasend),0,(struct sockaddr*)&cliaddr, &addrlen);
	msg_send.number = msg_recv.number + 1;
	msg_send.len = randvalue();
	printf("version:%3d\n",msg_recv.version);
	printf("type:%d\n",msg_recv.type);
	printf("len:%d\n",msg_recv.len);
	printf("number:%d\n",msg_recv.number);
	printf("data:%s\n",msg_recv.data);
 
	fprintf(fd,"version:%d\n",msg_recv.version);
	fprintf(fd,"type:%d\n",msg_recv.type);
	fprintf(fd,"len:%d\n",msg_recv.len);
	fprintf(fd,"number:%d\n",msg_recv.number);
	fprintf(fd,"data:%s\n",msg_recv.data);
	if (strcmp(msg_recv.data,"close") == 0)
		break;
	}
	fclose(fd);
	return 0;
}
 
uint8_t randvalue()
{
	srand(time(0)+1);
	return (rand() % 255);
}

自写一则单链表小程序

发现很多公司面试都喜欢考链表,实际项目中尽管需要自己写链表的时候比较少,但还是会经常用到,链表是一种常用的数据结构。有必要整理一下自己的思路,索性写了一个。包括了链表的初始化,插入,删除,查找,销毁,打印等基本功能,当然考虑了头尾中间等位置情况。仓促完成的简单代码,bug比较多,链表中只存储了一个整形的变量,没有做数据类型的判断,有时候会段错误也难免。已知的一个问题就是创建的链表在有销毁前如果再创建一个的话,会造成内存泄露,因为之前的链表没有销毁头指针便指向了新的位置,旧链表就永远找不到哦。这些问题留在以后实际用到的时候再考虑吧,应付面试这个足矣!

?Download node.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <stdio.h>
#include <stdlib.h>
typedef struct node_t {
	int value;
	struct node_t *next;
} node;
#define LENGTH sizeof(node)
 
node *init_node(){
  int node_length,n=0;
  node *head=NULL;
  node *node_temp1,*node_temp2;
  node_temp2=(node *)malloc(LENGTH);
  printf("node length want to create:");
  scanf("%d",&node_length);
  if(node_length<1){
    printf("no node to create!");
    exit(0);
  }
  while(n<node_length){
    node_temp1=(node *)malloc(LENGTH);
 
    printf("input NO.%d value:",n+1);
    scanf("%d",&node_temp1->value);
    node_temp1->next=NULL;
    if(n==0)
      head=node_temp1;
    else
      node_temp2->next=node_temp1;
    node_temp2=node_temp1;
    n++;
  }
  return head;
}
 
node *insert_node(node *head){
  int insert_value;
  node *temp_node1=head;
  node *temp_node2=(node *)malloc(LENGTH);
  node *temp_node3=NULL;
  printf("insert value:");
  scanf("%d",&insert_value);
  while(temp_node1!=NULL){
    if(temp_node1->value<insert_value){
      temp_node3=temp_node1;
      temp_node1=temp_node1->next;
    }
    else
      break;
  }
  temp_node2->value=insert_value;
  if(temp_node3==NULL){/*locate the first node*/
    temp_node3=head;
    temp_node2->next=temp_node3;
    head=temp_node2;
  }
  else if(temp_node1!=NULL){  /*locate the medium of head,insert between temp3 and temp1*/    
    temp_node2->next=temp_node3->next;
    temp_node3->next=temp_node2;
  }else{  /*locate the end of head*/
    temp_node2->next=NULL;
    temp_node3->next=temp_node2;
  }
  return head;
}
 
node *delete_node(node *head){
  int del_value;
  node *temp_node1=head;
  node *temp_node2;
  printf("input the delete value:");
  scanf("%d",&del_value);
  if(head->value==del_value){ /* delete the head of node*/
    temp_node2=head;
    head=head->next;
    return head;
  }
 
  while(temp_node1!=NULL){
    if(temp_node1->value!=del_value){
      temp_node2=temp_node1;
      temp_node1=temp_node1->next;
    }
    else
      break;
  }
  if(temp_node1!=NULL){
    temp_node2->next=temp_node1->next;
    free(temp_node1);
  }else
    printf("not find what you want to delete!\n");
  return head;
}
 
void search_node(node *head){
  int search_value,n=1;
  node *temp_node=head;
  printf("insert the value which you find:");
  scanf("%d",&search_value);
  while(temp_node!=NULL){
    if(temp_node->value!=search_value){
      temp_node=temp_node->next;
      n++;
    }
    else
      break;
  }
  if(temp_node!=NULL)
    printf("finded what you want.\nthe %d node`s value:%d\n",n,temp_node->value);
  else
    printf("not find!\n");
}
 
void print_node(node *head){
  if(head==NULL){
    printf("blank node!create first please!\n");
    return;
  }
  node *temp_node=head; 
  do{
    printf("value:%d\n",temp_node->value);
    temp_node=temp_node->next;
  } while(temp_node!=NULL);
}
 
node *destroy_node(node *head){
  if(head==NULL){
    printf("blank node!create first please!\n");
    return;
  }
  node *temp_node;
  do{
    temp_node=head->next;
    free(head);
    head=temp_node;
  }while(head!=NULL);
  return head;
}
 
int main(){
  int options;
  node *head=NULL;
loop:
  printf("select options:\t1:create 2:insert 3:delete 4:find 5:print 6:destory 7:exit\ninput options:");
  scanf("%d",&options);
  switch(options){
    case 1:
      head=init_node();
      break;
    case 2:
      head=insert_node(head);
      break;
    case 3:
      head=delete_node(head);
      break;
    case 4:
      search_node(head);
      break;
    case 5:
      print_node(head);
      break;
    case 6:
      head=destroy_node(head);
      break;
    case 7:
      printf("byebye!");
      return 0;
    default:
      printf("invalid options!");
  }
  goto loop;
}

ioctl及getifaddrs读取IPV4,IPV6网卡信息

使用ioctl的SIOCGIFCONF可以读取所有网卡信息。ioctl调用后返回指向ifconf的结构链表,其中包含了指向ifreq的结构指针。ifconf及ifreq定义在net/if.h中。

《UNIX网络编程》中提供了get_ifi_info函数的实现方法,使用这种方式来获取网络信息。在LINUX下,这种方式不能获得IPV6的网卡信息。《UNIX网络编程》中有如下描述:

在支持IPV6的系统中,没有关于对SIOCGIFCONF请求是否返回IPV6地址的标准。我们给支持IPV6的新系统增加了一个case语句, 这是为了预防万一。问题在于ifreq中的联合把返回的地址定义成一个通用的16字节套接口地址结构,适合16字节的IPV4 socket_in结构,但对于24字节的IPV6 socket_in6结构太小了。如果返回IPV6地址,将可能破环现有的在每个ifreq结构中采用固定大小的套接口地址结构的代码。

经测试,在fedor6-2.6.18kernel中无法返回ipv6地址,事实上,返回的地址簇总是AF_INET,而并非AF_INET6。
这种方法的实现代码如下:

继续阅读

关于const限定符及与指针搭配使用的一点记录

const限定符指定了一个变量为只读变量,是不允许被改变的,因此const变量在定义时就必须初始化。
const在与指针搭配时,使用将变的复杂和微妙。简单的说const搭配指针就会出现以下三种情况:

  • 指向const变量(对象)的指针
  • const指针
  • 指向const变量(对象)的const指针

1.指向const变量(对象)的指针
指针指向了const变量,例如 const int *ptr或者int const *ptr,这两种写法含义一样,这表示const限定了ptr所指向的数据类型,而并非ptr本身。即ptr本身并不是const.可以对ptr重新赋值,无需在定义时初始化。
指向const变量的指针可以指向一个const变量,也可以指向一个非const变量,当然指针类型与变量类型要一致。不管指向了一个const变量还是非const变量,任何企图通过这个指针去修改变量的值都会导致编译错误。同时,const变量只能赋给指向const变量的指针,赋给一个普通变量也是不允许的。

继续阅读

Linux多线程(1)

学习参考《linux高级程序设计卷一》

GNU/Linux 实现了 POSIX 标准线程 API。所有线程函数和数据类型都在<pthread.h>头文件中声明。这些线程相关的函数没有被包含在 C 标准库中,而是在libpthread 中,所以当链接程序的时候需在命令行中加入 -lpthread 以确保能正确链接。

1.创建线程

创建线程使用pthread_create函数,函数原型:

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg)

参数解释:
a.一个指向pthread_t 类型变量的指针,新线程的线程 ID 将存储在这里。
b.一个指向线程属性(thread attribute)对象的指针,这个对象控制着新线程与程序其它部分交互的具体细节。如果传递NULL 作为线程属性,新线程将被赋予一组默认线程属性。
c.一个指向线程函数的指针。这是一个普通的函数指针,类型如下:void* (*) (void*)。
d.一个线程参数,类型void*,不论你传递什么值作为这个参数,当线程开始执行的时候,它都会被直接传递给新的线程。

函数 pthread_create 会在调用后立刻返回,原线程会继续执行之后的指令。同时,新线程开始执行线程函数。Linux 异步调度这两个线程,因此你的程序不能依赖两个线程得到执行的特定先后顺序。

1.1线程参数传递

pthread_create的第四个参数为第三个参数(线程将要执行的函数)的参数,通常的做法是给线程函数定义一个结构以包含线程函数所期待的实际参数序列,给线程函数定义一个结构以包含线程函数所期待的实际参数序列。

1.2等待线程

因为线程共享了主线程的数据,尤其是当给线程传递了参数时,主线程必须等待线程执行完成后才可以退出,严格的说主线程必须在线程执行完成之前确保参数的完整,因为通常这些参数是在主线程中定义的。这类似于局部变量(当生命期结束的时候自动释放)和堆上分配的对象(通过free或者C++的delete手工释放)。务必确保这个变量不会被释放(甚至在其它线程中也不行!),直到你确定这个线程不会再使用它。
使用pthread_join(pthread_t thread,void **retval),强制主线程等待线程退出。

一个例子–主线程创建两个线程,一个输出x,另一个输出o。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h> 
#include <pthread.h>
 
/* print_function 的参数 */
struct char_print_parms
{
/* 用于输出的字符 */
char character;
/* 输出的次数 */
int count;
};
/* 按照 PARAMETERS 提供的数据,输出一定数量的字符到stderr。
PARAMETERS 是一个指向 struct char_print_parms 的指针 */
void* char_print (void* parameters)
{
/* 将参数指针转换为正确的类型 */
struct char_print_parms* p = (struct char_print_parms*) parameters;
int i;
for (i = 0; i &lt; p-&gt;count; ++i)
fputc (p-&gt;character, stderr);
return NULL;
}
/* 主程序 */
 
int main ()
{
pthread_t thread1_id;
pthread_t thread2_id;
struct char_print_parms thread1_args;
struct char_print_parms thread2_args;
/* 创建一个输出 30000 个 x 的线程 */
hread1_args.character = 'x';
thread1_args.count = 30000;
prhread_create (&amp;thread1_id, NULL, &amp;char_print, &amp;thread1_args);
 
/* 创建一个输出 20000 个 o 的线程 */
thread2_args.character = 'o';
thread2_args.count = 20000;
pthread_create (&amp;thread2_id, NULL, &amp;char_print, &amp;thread2_args);
/* 确保第一个线程结束 */
pthread_join (thread1_id, NULL);
/* 确保第二个线程结束 */
pthread_join (thread2_id, NULL);
/* 现在我们可以安全地返回 */
return 0;
}

1.3 线程取消

在一个线程中以另一个线程ID作为参数调用pthread_cancel可以取消另一个线程。但是,线程可能运行在一段不可分割的代码中,必须全部得到执行或者干脆不执行。例如,线程可能分配一些资源,使用并稍后释放它们。如果线程在中途被取消,它可能没有机会释放那些被分配的资源,从而导致资源的泄漏。为防止这种情况发生,一个线程可以控制自身是否可以被取消,以及何时允许取消操作。

线程可以调用pthread_setcancelstate和pthread_setcanceltype来决定自身是否允许被其他线程取消,及取消方式(PTHREAD_CANCEL_DEFERRED和PTHREAD_CANCEL_ASYNCHRONOUS)。

带有#和##符号的函数式宏展开步骤

在函数式宏定义中,#运算符用于创建字符串,#运算符后面应该跟一个形参(中间可以有空格或Tab),s将被作为一个字符串替换,并且s中的多个空格或tab将被替换为一个空格。
#define STR(s) # s
STR(hello world)
预处理后变为”hello world” 。
##运算符把前后两个预处理Token连接成一个预处理Token,和#运算符不同,##运算符不仅限于函数式宏定义,变量式宏定义也可以用。
先列出一个例子,当然这不是一段可执行的程序,甚至编译不了,只是为了说明宏展开的步骤问题,事实上这样的宏定义很多地方都能见到。

#define _sh(x) p_f(”n”,#x,”=%d, or %d\n”,n##x,alt[x])
#define sh(x) _sh(x)
#define NA 26
_sh(NA)
sh(NA)

可能发现第二行的定义有些多余,但结果却是截然不同的。
使用cpp命令做一下预处理就可以看到_sh(NA)和sh(NA)展开的不同,以下为展开结果。

p_f(”n”,”NA”,”=%d, or %d\n”,nNA,alt[26])
p_f(”n”,”26″,”=%d, or %d\n”,n26,alt[26])

下边分别说一下_sh(NA)和sh(NA)的展开步骤

_sh(NA)展开的步骤如下:
1.#x要替换成”NA”。
2.n##x要替换成nNA。
3.除了带#和##运算符的参数之外,其它参数在替换之前要对实参本身做充分的展开,所以应该先把NA展开成26再替换到alt[x]中x的位置。换言之,带有#和##的不会再进行二次替换。
4.现在展开成了p_f(”n” “NA” “=%d, or %d\n”,nNA,alt[26]),所有参数都替换完了,这时编译器会再扫描一遍,再找出可以展开的宏定义来展开,假设NA或alt是变量式宏定义,这时会进一步展开,但经#或##替换的除外,所以”NA”并没有成为”26“,nNA也没有被替换为n26。

sh(NA)展开的步骤如下:
1.用_sh(NA)替换sh(NA),并扫描,发现NA可以再展开,展开为_sh(26)
2. 展开_sh(26)为p_f(”n”,”26″,”=%d, or %d\n”,n26,alt[26])

所以,当期望宏替换为变量式宏的值而不是这个宏名,并且有#或者##在使用时,就要格外注意了,需要再加一条看似废话的宏定义。

另外,关于带有可变参数的函数在宏定义时,除了可以使用__VA_ARGS__来替代可变参数外,也可以使用##来连接。如下的两个宏定义是类似的

#define vprint(fmt, …) log_z(__FILE__,__LINE__,fmt,__VA_ARGS__)
#define vprint(fmt,args…) log_z(__FILE__,__LINE__,fmt,## args)

这个宏常用在日志函数中,调用vprint函数就加入了文件名和行号,方便debug,也可以加入__DATE__,__TIME__等等预定义变量,log_z函数实现如下

void log_z(char *fn,int ln,const char *fmt, …)
{
va_list ap;
char buf[4096];
va_start(ap,fmt);
vsnprintf(buf,4096,fmt,ap);
printf(”[%s %d]“,fn,ln);
printf(buf);
printf(”\n”);
}

另一个更加简单有效的增加行号的做法是这样定义的

#define vprint(fmt,args…) printf(”[%s %d]“fmt,__FILE__,__LINE__,##args)

动态库静态库的编译和使用方法学习记录

本文参考资料:《Linux编程一站式学习》 版权 © 2008, 2009 宋劲杉, 北京亚嵌教育研究中心
部分内容摘自此文

有时候需要把一组代码编译成一个库,这个库在很多项目中都要用到,例如libc就是这样一个库,我们在不同的程序中都会用到libc中的库函数(例如printf),也会用到libc中的变量。
学习中用到的一个简单的小程序,程序将字符a,b,c压入堆栈stack[512],随后再倒序输出,打印出cba。为了使用到的gcc命令更具有意义,特意将程序分开在了几个C文件中,最后将几个.o文件链接为可执行文件。
stack.c

char stack[512];
int top = -1;

pop.c

extern int top;
extern char stack[512];
char pop(void)
{
return stack[top--];
}

push.c

extern int top;
extern char stack[512];
void push(char c)
{
stack[++top]=c;
}

继续阅读

递归程序的困扰

很久没有写过递归程序,今天被一个小小的递归给困扰了。请教了CSDN的大哥们后,终于想明白了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.c>
#define LEN 3
 
char buf[LEN]={'a','b','c'};
 
void print_backward(int pos)
{
  if (pos == LEN)
    return;
  print_backward(pos+1);
  putchar(buf[pos]);
}
 
int main(void)
{
  print_backward(0);
  putchar('\n');
 
  return 0;
}

其实挺简单的,就是return是return到上次调用的,加上main里的调用,一共调用了4次,第4次时pos=3,直接返回到第三次,第三次就执行了 putchar(buf[pos]);,而此时pos=2,也就是执行了 putchar(buf[2]);,依次类推,分别输出了buf[1],buf[0],最后返回到了Main函数。
递归很强大,有时候很费解,这样的写法还是要学会的。

MD5应用的一点理解及Linux实现源码

MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),相关的标准是RFC1321,MD5的算法描述可以查看这份RFC或者自己google,这里就不提这些概念性的问题了。

需要说明的是MD5加密是单向不可逆的,也就是说没有办法把已经加密的密文还原为明文。所以最常见的应用在于用户名密码在数据库中的保存,一般的做法是将密码用MD5加密后将密文存入数据库,用户登陆时再将用户输入的明文密码做MD5运算后与数据库进行密文比照,密文比照不符则证明密码输入错误了。所以如果密码丢失了就只能重置,没有人会知道数据库中保存的密文所对应的明文。网上有看到说破解,这个不想做过多研究,仅凭一点经验理解,基本知道只要明文设置的复杂一些,解密几乎是不可能的事情。

最近在做UDP传输过程中的MD5校验,即是将所传输的数据(大约10KB的字串)进行MD5运算,然后把10KB的数据和32位长的MD5值一并发向客户端,客户端收到后再对所收到的10KB字串做MD5运算,与传输过来的MD5值比对,就可知道收到的数据是否有误需要丢弃或通知重传了。或许传输过来的MD5也会有误,不知道这样的问题IETF是怎么考虑的,知道的麻烦告知。

以下是自己整理的一份对字符串MD5加密的源码,留备记录。

md5.h

#ifndef MD5_H
#define MD5_H
 
#ifdef __alpha
typedef unsigned int uint32;
#else
typedef unsigned long uint32;
#endif
 
struct MD5Context {
	uint32 buf[4];
	uint32 bits[2];
	unsigned char in[64];
};
 
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
	       unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
void MD5Transform(uint32 buf[4], uint32 const in[16]);
 
/*
 * This is needed to make RSAREF happy on some MS-DOS compilers.
 */
typedef struct MD5Context MD5_CTX;
 
#endif /* !MD5_H */

md5.c

/*
 * This code implements the MD5 message-digest algorithm.
 * The algorithm is due to Ron Rivest.  This code was
 * written by Colin Plumb in 1993, no copyright is claimed.
 * This code is in the public domain; do with it what you wish.
 *
 * Equivalent code is available from RSA Data Security, Inc.
 * This code has been tested against that, and is equivalent,
 * except that you don't need to include two pages of legalese
 * with every copy.
 *
 * To compute the message digest of a chunk of bytes, declare an
 * MD5Context structure, pass it to MD5Init, call MD5Update as
 * needed on buffers full of bytes, and then call MD5Final, which
 * will fill a supplied 16-byte array with the digest.
 */
#include <string.h>		/* for memcpy() */
#include "md5.h"
 
#ifndef HIGHFIRST
#define byteReverse(buf, len)	/* Nothing */
#else
void byteReverse(unsigned char *buf, unsigned longs);
 
#ifndef ASM_MD5
/*
 * Note: this code is harmless on little-endian machines.
 */
void byteReverse(unsigned char *buf, unsigned longs)
{
    uint32 t;
    do {
	t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
	    ((unsigned) buf[1] << 8 | buf[0]);
	*(uint32 *) buf = t;
	buf += 4;
    } while (--longs);
}
#endif
#endif
 
/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
 */
void MD5Init(struct MD5Context *ctx)
{
    ctx->buf[0] = 0x67452301;
    ctx->buf[1] = 0xefcdab89;
    ctx->buf[2] = 0x98badcfe;
    ctx->buf[3] = 0x10325476;
 
    ctx->bits[0] = 0;
    ctx->bits[1] = 0;
}
 
/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
 */
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
    uint32 t;
 
    /* Update bitcount */
 
    t = ctx->bits[0];
    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
	ctx->bits[1]++;		/* Carry from low to high */
    ctx->bits[1] += len >> 29;
 
    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
 
    /* Handle any leading odd-sized chunks */
 
    if (t) {
	unsigned char *p = (unsigned char *) ctx->in + t;
 
	t = 64 - t;
	if (len < t) {
	    memcpy(p, buf, len);
	    return;
	}
	memcpy(p, buf, t);
	byteReverse(ctx->in, 16);
	MD5Transform(ctx->buf, (uint32 *) ctx->in);
	buf += t;
	len -= t;
    }
    /* Process data in 64-byte chunks */
 
    while (len >= 64) {
	memcpy(ctx->in, buf, 64);
	byteReverse(ctx->in, 16);
	MD5Transform(ctx->buf, (uint32 *) ctx->in);
	buf += 64;
	len -= 64;
    }
 
    /* Handle any remaining bytes of data. */
 
    memcpy(ctx->in, buf, len);
}
 
/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern 
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
    unsigned count;
    unsigned char *p;
 
    /* Compute number of bytes mod 64 */
    count = (ctx->bits[0] >> 3) & 0x3F;
 
    /* Set the first char of padding to 0x80.  This is safe since there is
       always at least one byte free */
    p = ctx->in + count;
    *p++ = 0x80;
 
    /* Bytes of padding needed to make 64 bytes */
    count = 64 - 1 - count;
 
    /* Pad out to 56 mod 64 */
    if (count < 8) {
	/* Two lots of padding:  Pad the first block to 64 bytes */
	memset(p, 0, count);
	byteReverse(ctx->in, 16);
	MD5Transform(ctx->buf, (uint32 *) ctx->in);
 
	/* Now fill the next block with 56 bytes */
	memset(ctx->in, 0, 56);
    } else {
	/* Pad block to 56 bytes */
	memset(p, 0, count - 8);
    }
    byteReverse(ctx->in, 14);
 
    /* Append length in bits and transform */
    ((uint32 *) ctx->in)[14] = ctx->bits[0];
    ((uint32 *) ctx->in)[15] = ctx->bits[1];
 
    MD5Transform(ctx->buf, (uint32 *) ctx->in);
    byteReverse((unsigned char *) ctx->buf, 4);
    memcpy(digest, ctx->buf, 16);
    memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
}
 
#ifndef ASM_MD5
 
/* The four core functions - F1 is optimized somewhat */
 
/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
 
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
 
/*
 * The core of the MD5 algorithm, this alters an existing MD5 hash to
 * reflect the addition of 16 longwords of new data.  MD5Update blocks
 * the data and converts bytes into longwords for this routine.
 */
void MD5Transform(uint32 buf[4], uint32 const in[16])
{
    register uint32 a, b, c, d;
 
    a = buf[0];
    b = buf[1];
    c = buf[2];
    d = buf[3];
 
    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
 
    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
 
    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
 
    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
 
    buf[0] += a;
    buf[1] += b;
    buf[2] += c;
    buf[3] += d;
}
 
#endif

md5test.c

#include <stdio.h>
#include <string.h>
#include "md5.h"
 
void md5str(char* str){
	int i;
	unsigned char chappassword[16];
	unsigned int len=strlen(str);
	MD5_CTX context;
	MD5Init(&context);
	MD5Update(&context,(const unsigned char*)str,len);
 
	MD5Final(chappassword,&context);
	for(i=0;i<16;i++)
		printf("%02x",chappassword[i]);
	printf("\n");
}
int main(){
	char* password="hello";
	md5str(password);
}

ioctl对madwifi驱动网卡的SSID设置操作

下面一则小程序实现了对无线网卡的SSID设置操作,网卡使用madwifi-hal-0.10.5.6驱动。其中wireless_copy.h头文件在madwifi/tools下,需要将这个头文件包含在这则小程序中。更多的其他诸如channel的设置,请参考http://gattaca.ru/~nikki/wrt54g/wpa/x/wpa_supplicant/driver_wext.c

以下为程序源码,与大家共享
get_set_ssid.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <stdio .h>
#include <stdlib .h>
#include <sys /socket.h>
#include <string .h>
#include "wireless_copy.h"
 
int get_essid(int sock, struct iwreq* wrq,char* ssid);
int set_essid(int sock, struct iwreq* wrq,char* value);
 
int main(){
 
	struct iwreq wrq;
	int i,sock;
	char gInterfaceName[16];
	char *ssid=(char *)malloc(sizeof(char)*(32+1));
	char *set_ssid="testssid";
 
	memset(ssid,0,sizeof(ssid));
	memset(gInterfaceName, 0, sizeof(gInterfaceName));
	strcat(gInterfaceName,"ath0");
 
	sock = socket(AF_INET, SOCK_DGRAM, 0);
		if (sock < 0) 
		{
			printf("Error Creating Socket for ioctl\n"); 
			return 0;
		}
	memset(&wrq, 0, sizeof(wrq));
	strncpy(wrq.ifr_name, gInterfaceName, IFNAMSIZ);
//get ssid
	get_essid(sock, &wrq,ssid);
 
	printf("old ssid:%s\n",wrq.u.essid.pointer);
	free(ssid);
//reset struct
	memset(&wrq, 0, sizeof(wrq));
	strncpy(wrq.ifr_name, gInterfaceName, IFNAMSIZ);
//set ssid	
	set_essid(sock, &wrq,set_ssid);
 
	printf("new ssid:%s\n",wrq.u.essid.pointer);
}
 
 
int get_essid(int sock, struct iwreq* wrq,char* ssid)
{
 
	wrq->u.essid.length=32;
	wrq->u.essid.pointer=(caddr_t) ssid;
      	if(ioctl(sock, SIOCGIWESSID, wrq) < 0)
	{
		perror("Ioctl error");
		free(ssid);
		return(0);
	}	
 
	printf("\nssid from function get_ssid: %s\n", wrq->u.essid.pointer);
 
	return 1;
}
 
int set_essid(int sock, struct iwreq* wrq,char* value)
{
	wrq->u.essid.pointer=value;
	wrq->u.essid.length=strlen(value);
	wrq->u.essid.flags=1;
      	if(ioctl(sock, SIOCSIWESSID, wrq) < 0)
	{
		perror("Ioctl error");
		return(0);
	}	
 
	printf("\nessid from function set_essid: %s\n", wrq->u.essid.pointer);
 
	return 1;
}
</string></sys></stdlib></stdio>

继续阅读

Page 1 of 212