[C言語]バイナリファイル

パケットフィルタリングとは、通信機器やコンピュータの持つネットワーク制御機能の一つで、外部から受信したデータを管理者が設定した一定の基準に従って通したり破棄したりすること
Berkeley Packet Filterとは、ユーザランドからのコードをカーネル内で安全に実行する為の仕組み

$ grep BPF /boot/config-`uname -r`
CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
CONFIG_TEST_BPF=m

#include 
#include 
#include 
#include 
#include "bpf_load.h"
#include "sock_example.h"
#include 
#include 

int main(int ac, char **argv){

	char filename[256];
	FILE *f;
	int i, sock;

	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

	if(load_bpf_file(filename)){
		printf("%s", bpf_log_buf);
		return 1;
	}

	sock = open_raw_sock("lo");

	assert(setsockopt(sock, SQL_SOCKET, SO_ATTACH_BPF, prog_fd, sizeof(prog_fd[0])) == 0);

	f = popen("ping -c5 localhost", "r");
	(void) f;

	for(i = 0; i < 5; i++){
		long long tcp_cnt, udp_cnt, icmp_cnt;
		int key;

		key = IPPROTO_TCP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &tcp_cnt) == 0);

		key = IPPROTO_UDP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &udp_cnt) == 0);

		key = IPPROTO_ICMP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &icmp_cnt) == 0);

		printf("TCP %lld UDP %lld ICMP %lld bytes\n", tcp_cnt, udp_cnt, icmp_cnt);
		sleep(1);
	}

	return 0;
}

TCPとはIPと同様にインターネットにおいて標準的に利用されている プロトコル。TCPは、IPの上位プロトコルでトランスポート層で動作する。
ネットワーク層のIPとセッション層以上のプロトコル(HTTP、FTP、Telnetなど)の橋渡しをする

UDPはUser Datagram Protocolの略、アプリケーション同士が最小限の仕組みでデータを送受信するプロトコル、リアルタイム性が重要視される通信で使われる、送信者アドレスの偽装が容易であるためDNSなどを使ったDDoS攻撃で使われることも多い

ICMPはIPプロトコルの「エラー通知」や「制御メッセージ」を転送するためのプロトコル、TCP/IPが実装されたコンピュータ間で通信状態を確認するために使用

[C言語]バイナリファイル

0と1のビットの並びで表現されたファイルをバイナリファイルと呼ぶ。また、そのデータをバイナリデータと呼ぶ。
行を変えるという概念がない。

– エンディアン
2バイト以上あるデータをメモリ上に配置する時に、どのように並べるかというルールのことで、リトルエンディアンとビッグエンディアンがある。
「0x00 0x00 0x003 0x84」(ビッグエンディアン)と「0x84 0x003 0x00 0x00」(リトルエンディアン)
IntelのCPUはリトルエンディアン

#include <stdio.h>

int main(void){
	printf("%X\n", 'x');
	printf("%X\n", 'y');
	printf("%X\n", 'z');
}

– 読み書き
fopen関数に”b”を含む

#include
#include

int main(void){
FILE *fp = fopen(“test.bin”,”rb”);
if(fp == NULL){
fputs(“ファイルオープンに失敗しました。\n”, stderr);
exit(EXIT_FAILURE);
}

int num = 900;
double d = 7.85;
char str[] = “xyzxyz”;

if(fwrite(&num, sizeof(num), 1, fp) < 1){ fputs("1.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fwrite(&d, sizeof(d), 1, fp) < 1){ fputs("2.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fwrite(str, sizeof(str[0]),sizeof(str),fp) < sizeof(str)){ fputs("3.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fclose(fp) == EOF){ fputs("ファイルクローズに失敗しました。\n", stderr); exit(EXIT_FAILURE); } return 0; } [/code] $ ./test 1.ファイル書き込みに失敗しました。

[C言語]データベース

### 作り方
データを構造体配列にして検索で工夫する
データのレコードやデータベースの項目情報は動的メモリ確保されたメモリ領域にリスト構造で保持
そこから検索アルゴリズムでデータを取り出し、必要に応じてソート処理
データの保存・読み込みにはバイナリファイルの取り扱いノウハウが必要

### 必要知識
検索、リスト構造、ソート、ハッシュ、動的メモリ確保、バイナリファイルの取り扱い

### 構造体配列のサンプル

#include <stdio.h>

struct pop_dt {
	char region[20];
	long pop;
};

int main(void){

	struct pop_dt world[7] = {
		{"asia", 3769},
		{"north_america", 498},
		{"south_america", 357},
		{"europe", 725},
		{"africa", 832},
		{"oceania", 31},
		{"nowhere", 0}
	};

	int i;
	for(i=0; world[i].pop != 0; i++){
		printf("%-15s %6d\n", (world+i)->region, (world+i)->pop);
	}

	return 0;
}

$ ./main
asia 3769
north_america 498
south_america 357
europe 725
africa 832
oceania 31

一つの事をやろうとしたら、副次的に色々な事を学ばなければならない。その量がやたら多いように感じるのは実力がないからか。

[C言語]Webサーバー

IPv4とは?
-> データ通信規格。IPアドレスを32ビットのデータとして扱う
バイトストリームとは?
-> バイト単位のデジタルデータのひと続き

#include 
#include  // typedefシンボルおよび構造体のコレクションを定義
#include  // ソケットに使うためのヘッダファイル socket()
#include  // インターネット・プロトコル・ファミリーの定義


int main(void){

	int rsock, wsock;
	struct sockaddr_in addr, client;
	int len;
	int ret;

	// 通信をするためのソケット作成
	rsock = socket(AF_INET, SOCK_STREAM, 0); // AF_INETはIPv4接続、SOCK_STREAMはバイトストリーム

	if(rsock < 0){
		fprintf(stderr, "Error. Cannot make socket\n");
		return -1;
	}

	// socket設定
	addr.sin_family = AF_INET; // IPv4
	addr.sin_port = htons(8080); // 8080ポート
	addr.sin_addr.s_addr = INADDR_ANY;  // アドレス指定なし

	// binding socket
	bind(rsock, (struct sockaddr *)&addr, sizeof(addr));

	if(ret < 0){
		fprintf(stderr, "Error. Cannot bind socket\n");
		return -1;
	} 

	// socketの接続待ち
	listen(rsock, 5);

	// accept TCP connection from client
	len = sizeof(client);
	wsock = accept(rsock, (struct sockaddr *)&client, &len);

	// メッセージ送信
	write(wsock, "HTTP1.1 200 OK", 14);

	// TCPセッション終了
	close(wsock);
	close(rsock);

	return 0;
}

$ gcc -o main main.c
main.c: In function ‘main’:
main.c:43:2: warning: implicit declaration of function ‘write’; did you mean ‘fwrite’? [-Wimplicit-function-declaration]
write(wsock, "HTTP1.1 200 OK", 14);
^~~~~
fwrite
main.c:46:2: warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration]
close(wsock);
^~~~~
pclose

ソケットで通信していることはわかったが、よくわからん。

[C言語]タグの中身をパースする

Webブラウザを作りたい
まず基本として、タグを表示させます

#include <stdio.h>

void parse_element(char *c){
	printf("%s\n", c);
}

int main(){

	char c[256] = "<html>Hello</html>";

	parse_element(c);

	return 0;
}

ここから、charのタグの中身をくりとります。
strchrで “>” 以降を取得して、先頭文字を削除し、”<" 以前を表示させます。

#include 
#include 

void parse_element(char *c){
	int len, i, j, k;
	char *tag;
	char moji[256];
	tag = strchr(c, (int)’>’);
	len = strlen(tag);
	for(i=1; i < len; i++){
		j = i-1;
		moji[j] = tag[i];
	}
	k = 0;
	while(moji[k] != '<'){
		printf("%c", moji[k]);
		k++;
	}
	printf("\n");

}

int main(){

	char c[256] = "Hello“;

	parse_element(c);

	return 0;
}

$ ./main
Hello

“<"と">“でパースして処理をしているのか。
Webブラウザって相当難しいね

[C言語]整数比の直角三角形

直角三角形はピタゴラスの定理が成り立つ
a^2 + b^2 = c^2

#include 

int main(){

	int a, a2, b, b2, c;

	printf("整数比の直角三角形を探索");

	for(a=1; a<= 100; a++){
		a2 = a*a;
		for(b=a; b<=100; b++){
			b2 = b*b;
			for(c=b+1; c<=100;c++){
				if(a2+b2 == c*c){
					printf("%d:%d:%d\n",a, b, c);
				}
			}
		}
	}

	return 0;
}

$ ./main
整数比の直角三角形を探索3:4:5
5:12:13
6:8:10
7:24:25
8:15:17
9:12:15
9:40:41
10:24:26
11:60:61
12:16:20
12:35:37
13:84:85
14:48:50
15:20:25
15:36:39
16:30:34
16:63:65
18:24:30
18:80:82
20:21:29
20:48:52
21:28:35
21:72:75
24:32:40
24:45:51
24:70:74
25:60:65
27:36:45
28:45:53
28:96:100
30:40:50
30:72:78
32:60:68
33:44:55
33:56:65
35:84:91
36:48:60
36:77:85
39:52:65
39:80:89
40:42:58
40:75:85
42:56:70
45:60:75
48:55:73
48:64:80
51:68:85
54:72:90
57:76:95
60:63:87
60:80:100
65:72:97

こんなにあるのか

[C言語]簡易電卓

#include 
#include 

int main(){

	char c[128],c1[128],op;
	int x=0, y=0, z=0,i=0, j;

	printf("計算式:\n");
	gets(c);

	for(j=0; c[i]>='0' && c[i]<='9'; i++){
		c1[j]=c[i];
		j++;
	}
	c1[j] = '\0'; x=atoi(c1);  // \0はNULL

	op = c[i]; i++;

	for(j=0; c[i]>='0' && c[i]<='9'; i++){ // iは第1項とoperandの次の配列から
		c1[j]=c[i];
		j++;
	}
	c1[j] = '\0'; y=atoi(c1);

	switch(op){
		case '+': z=x+y; break;
		case '-': z=x-y; break;
		case '*': z=x*y; break;
		case '/': z=x/y; break;
		case '%': z=x%y; break;
		default: printf("\a");
	}
	printf("answer: %d\n", z);

	return 0;
}

$ ./main
計算式:
22+3
answer: 25

forループを二回回しているが、2回目のiは第1項とoperandの次の配列からのiとなる
一見あれ?っと思った。

[C言語]無限ループ

#include <stdio.h>

int main(){

	char muki="L";
	int kn;

	while(1){
		system("cls");
		if(muki == 'L'){
			printf("                     \n");
            printf(" ***                 \n");
            printf("    *                \n");
            printf("     *********       \n");
            printf("      ******         \n");
            printf("       *  *          \n");
            printf("      *    *         \n");
            printf("_y_y_y*y_y_y*y_y_y_y_\n");
		} else if(muki == 'R'){
			printf("                     \n");
            printf("              ***    \n");
            printf("             *       \n");
            printf("    *********        \n");
            printf("      ******         \n");
            printf("       *  *          \n");
            printf("      *    *         \n");
            printf("_y_y_y*y_y_y*y_y_y_y_\n");
		}

		printf("\n");
		printf("<-で左向き、->で右向き、Escキーで終了\n");

		scanf("%d", &kn);
		if(kn == 27) break;  // Escキー
		if(kn!= 0) continue;

		if(kn == 77) muki="R";
		if(kn == 75) muki="L";
	}

	return 0;
}

<-で左向き、->で右向き、Escキーで終了
sh: 1: cls: not found

<-で左向き、->で右向き、Escキーで終了
sh: 1: cls: not found

<-で左向き、->で右向き、Escキーで終了
sh: 1: cls: not found

<-で左向き、->で右向き、Escキーで終了
sh: 1: cls: not found

<-で左向き、->で右向き、Escキーで終了
sh: 1: cls: not found

<-で左向き、->で右向き、Escキーで終了
sh: 1: cls: not found

<-で左向き、->で右向き、Escキーで終了

コンピュータが悲鳴を上げました。
scanf(“%d”, &kn);だと、32764となる
$ ./main
^[[C
32764

あ、キーコード取得はgetchar()だ。scanf()とこんがらがる。

#include 

int main(){

	int kn;

	kn = getchar();
	printf("%d", kn);

	return 0;
}

$ ./main
a
$ ./main
^[[C
27

[C言語]配列のアスキー

#include 
#include 
#include 
#include 

char buf[25][80];

void Gen_line(int,int,int,int);

int main(){

	int x1=5, y1=0;
	int x2=25, y2=0;
	int x3=30, y3=10;
	int y;

	memset(&buf[0][0],' ',25*80); 

	Gen_line(x1,y1,x2,y2);
	Gen_line(x2,y2,x3,y3);
	Gen_line(x3,y3,x1,y1);

	for(y=24; y > =0; y--){
		printf("%.80s",&buf[y][0]);
	}
	fflush(stdout);

	return 0;
}

void Gen_line(int xS, int yS, int xE, int yE){
	double dx, dy, a = 0, b=0;
	int x,y;

	buf[yS][xS]='*';
	buf[yE][xE]='*';

	if(xS==xE){
		if(yS > yE){
			y = yS; yS = yE; yE=y;}
			for(y=yS+1; y xE){
				x=xS; xS=xE;xE=x;y=yS;yS=yE;yE=y;
			}
			dx=xE-xS; dy=yE-yS;
			a=dy/dx; b=yS-a*xS;

			for(x = xS+1; x < xE; x++){
				y=a*x + b + 0.5;
				buf[y][x]= '*';
			}
		}
	}

$ ./main
** ** *** * ** *** * ** *** * ** *** * ** *********************

三角形になってる? 意味がわからん

[C言語]2進数から10進数への変換

#include <stdio.h>
#include <stdlib.h>

int main(){

	char c[128];
	int i, n;

	printf("2進数に10進数に変換します\n");
	printf("2進数:\n");fflush(stdout);

	gets(c);
	// scanf("%d",&n);
	i=0; n=0;

	while(1){
		if(c[i]=='1') n = n+1;

		i=i+1;
		if(c[i]=='\0') break;
		n=n*2;
	}
	printf("10進数=%d\n", n);

	return 0;
}

$ ./main
2進数に10進数に変換します
2進数:
11111
10進数=31