2012年10月24日 星期三

Passing string as -D compiler flag to .c

有時候有些字串需要compiler time時決定。通常前期先用menuconfig之類的工具設定好,再進行compile動作,此時新字串就會自動帶進.c中。

要做到這樣的效過,在gcc中可以用-D方式指定。

gcc編譯中加入 -DNEW_STRING=\"xxxxxxx\"。

在c原始碼內,利用一些字串連接的技巧串起來。或者可以自己加入#define中。

char a* = "I got "NEW_STRING"!!!!";

這樣目的就達成了。


參考資料
[1] Passing string as -D compiler option

2012年8月26日 星期日

Linux get ipv6 default route

在ipv6情況下可以從/proc/net/ipv6_route印出當前default route資訊。試了一下發現內容順序以及值會跟隨目前routing作改變。在參考了route_linux.c以及how to get ipv6 default gateway from proc in linux之後,改寫出以下範例。

int getIpv6DefaultGatway(char *ifname, char *dgw, int dgw_size){
struct in6_addr src_addr;
int src_prefix;
struct in6_addr dst_addr;
int dst_prefix;
struct in6_addr gw_addr;
struct in6_addr any_addr;
unsigned int metrix;
unsigned int ref_cnt;
unsigned int usr_cnt;
unsigned int flag;
char devname[32];
FILE *fp;
int ret;
char dst[64];
char src[64];
char gw[64];

if(ifname == NULL){
return 0;
}

strcpy(dgw, "");

fp = fopen("/proc/net/ipv6_route", "r");
if(fp!=NULL){
memset(&any_addr, 0, sizeof(any_addr));
while((ret=fscanf(fp, "%s %x %s %x %s %x %x %x %x %s",
dst, &dst_prefix, src, &src_prefix, gw,
&metrix, &ref_cnt, &usr_cnt, &flag, devname)) != EOF){


/*return value must be parameter's number*/
if(ret != 10){
continue;
}

/*default route?*/
if(!strncmp(gw, "fe80", 4)
&& !strcmp(dst, "00000000000000000000000000000000") && dst_prefix == 0
&& !strcmp(ifname, devname)){


sprintf(gw, "%c%c%c%c:%c%c%c%c:%c%c%c%c:%c%c%c%c:%c%c%c%c:%c%c%c%c:%c%c%c%c:%c%c%c%c",
gw[0], gw[1], gw[2], gw[3], gw[4], gw[5], gw[6], gw[7], gw[8], gw[9],
gw[10], gw[11], gw[12], gw[13], gw[14], gw[15], gw[16], gw[17], gw[18], gw[19],
gw[20], gw[21], gw[22], gw[23], gw[24], gw[25], gw[26], gw[27], gw[28], gw[29],
gw[30], gw[31]);

inet_pton(PF_INET6, gw, &gw_addr);
inet_ntop(PF_INET6, &gw_addr, gw, sizeof(gw));

snprintf(dgw, dgw_size, "%s", gw);

//DO NOT BREAK to get last gateway
}
}
}
fclose(fp);

if(!strcmp(dgw, "")){
return 0;
}

return 1;
}

2012年8月21日 星期二

exec, spawn, system不同點

根據stackoverflow中Difference b/w exec( ) and system( ) in unix這篇文章中討論到的

exec: 覆蓋原本的程式,執行完即結束。

spawn: 啟動一個新的子程式(fork效用相當),並且和原本的程式同時進行。

system: 啟動一個新的子程式(fork效用相當),並且原本程式會等待該子程式執行完後才結束。

2012年7月25日 星期三

Find process and send signal to it in Kernel

工作上覺得還蠻實用的程式片段。

struct task_struct *p;  
struct siginfo info;

pid_t pid = -1;

for_each_process(p) {
if (!strcmp(p->comm, "process name")){
pid = p->pid;
break;
}
}


if(pid != -1){

if(p != NULL) {
info.si_signo = SIGUSR1;
info.si_code = SI_QUEUE;
info.si_int = 0x3;
send_sig_info(SIGUSR1, &info, p);

printk(KERN_EMERG "Send SIGUSR1 with value %d to %s(%d)\n", info.si_int, "process name", pid);
}

}

Netlink 使用方法

Kernel Korner - Why and How to Use Netlink Socket這篇寫得非常好,關於netlink的使用方法,範例也非常簡潔易懂。

這裡就貼上關於不使用group方式process送訊息至kernel。

User Space

#include <sys/socket.h>
#include <linux/netlink.h>

#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;

void main() {
sock_fd = socket(PF_NETLINK, SOCK_RAW,NETLINK_TEST);

memset(&src_addr, 0, sizeof(src_addr));
src__addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* self pid */
src_addr.nl_groups = 0; /* not in mcast groups */
bind(sock_fd, (struct sockaddr*)&src_addr,
sizeof(src_addr));

memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* For Linux Kernel */
dest_addr.nl_groups = 0; /* unicast */

nlh=(struct nlmsghdr *)malloc(
NLMSG_SPACE(MAX_PAYLOAD));
/* Fill the netlink message header */
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid(); /* self pid */
nlh->nlmsg_flags = 0;
/* Fill in the netlink message payload */
strcpy(NLMSG_DATA(nlh), "Hello you!");

iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;

sendmsg(fd, &msg, 0);

/* Read message from kernel */
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
recvmsg(fd, &msg, 0);
printf(" Received message payload: %s\n",
NLMSG_DATA(nlh));

/* Close Netlink Socket */
close(sock_fd);
}

Kernel Space

struct sock *nl_sk = NULL;

void nl_data_ready (struct sock *sk, int len)
{
wake_up_interruptible(sk->sleep);
}

void netlink_test() {
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh = NULL;
int err;
u32 pid;

nl_sk = netlink_kernel_create(NETLINK_TEST,
nl_data_ready);
/* wait for message coming down from user-space */
skb = skb_recv_datagram(nl_sk, 0, 0, &err);

nlh = (struct nlmsghdr *)skb->data;
printk("%s: received netlink message payload:%s\n",
__FUNCTION__, NLMSG_DATA(nlh));

pid = nlh->nlmsg_pid; /*pid of sending process */
NETLINK_CB(skb).groups = 0; /* not in mcast group */
NETLINK_CB(skb).pid = 0; /* from kernel */
NETLINK_CB(skb).dst_pid = pid;
NETLINK_CB(skb).dst_groups = 0; /* unicast */
netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);
sock_release(nl_sk->socket);
}

2012年7月12日 星期四

ipv6 pton空字串

當inet_pton進一個空字串再反向inet_ntop回來時,值會變怎樣呢?
範例程式碼如下
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
int main()
{
    unsigned char a[16];
    char b[64] = "";
    char c[64] = "";
    
    
    inet_pton(PF_INET6, b, &a);
    inet_ntop(PF_INET6, b, c, sizeof(c));
    
    fprintf(stderr, "c is %s\n", c);
    
    return 0;
}

結果:
./ntop_test 
c is ::

2012.7.12更新
在這個範例中inet_pton轉換空字串其實是失敗的,並沒有寫入a中。
其實::的結果是c為空字串轉換回去的結果。

2012年5月25日 星期五

ipv6位址比較

ipv4因為sin_addr中s_addr結構為uint32,可以利用"等於"直接作位址比較。

typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr; /* IPv4 address */
};

比較方式可以像下面這樣。

(sa->sin_addr.s_addr != (((struct sockaddr_in *)&remote)->sin_addr.s_addr))

但是v6中sin6_addr就長得不太一樣了。

struct in6_addr {
union {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];
} in6_u;

    #define s6_addr in6_u.u6_addr8
    #define s6_addr16 in6_u.u6_addr16
    #define s6_addr32 in6_u.u6_addr32
};

可以看到是使用陣列方式儲存。比較的話要使用memcmp方式來達成。

memcmp(sa_v6->sin6_addr.s6_addr, (((struct sockaddr_in6 *)&remote)->sin6_addr.s6_addr), 16) != 0

這個問題的來源可以參考Comparing a peer's IPv6 address with localhost

2012年5月24日 星期四

Porting applications to IPv6 HowTo

這次是要在linux下將ipv4的程式改成ipv4/ipv6相容的程式。

原文可以看Porting applications to IPv6 HowTo

首先利用sockaddr_storage取代傳統的sockaddr_in。當使用ipv4做溝通時,就將這個struct轉為sockaddr_in,使用ipv6溝通時,就要轉換為sockaddr_in6。sockaddr_storage裏面構造長得很像sockaddr_in和sockaddr_in6。

#if ULONG_MAX > 0xffffffff
# define __ss_aligntype __uint64_t
#else
# define __ss_aligntype __uint32_t
#endif
#define _SS_SIZE 128
#define _SS_PADSIZE (_SS_SIZE - (2 * sizeof (__ss_aligntype)))

struct sockaddr_storage
{
sa_family_t ss_family; /* Address family */
__ss_aligntype __ss_align; /* Force desired alignment. */
char __ss_padding[_SS_PADSIZE];
};

當我要使用的時候,我可以預先做轉好的動作備用。

struct sockaddr_storage sa;
struct sockaddr_in *sa_v4 = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sa_v6 = (struct sockaddr_in *)&sa;

或是你需要用的時候再做轉換。

(((struct sockaddr_in *)&sa)->sin_addr.s_addr)     --->v4
(((struct sockaddr_in6 *)&sa)->sin6_addr.s6_addr) --->v6

接著,記得系統要build好ipv6的module,那樣的話,bind, recv這些通訊方法通通不用改。


而要分辨現在溝通模式是v4還是v6,可以看ss_family。

if(sa.ss_family == AF_INET){
...
}else if(sa.ss_family == AF_INET6){
...
}

最後就要有耐心的補完v6的邏輯。因為網路位址轉字串,位址比較都和v4不相同。詳細範例可以再看前面提到的Porting applications to IPv6 HowTo

(pre)Maturely Optimize Your JavaScript

http://msdn.microsoft.com/zh-tw/magazine/gg622887(en-us).aspx

這篇說到javasscript運行的最佳化。

裡面說了一些觀念。不要為了很少執行到的程式作最佳化。在寫程式時就要想好比較省的想法。

舉了一些範例。
1. loop減少function call的重複性呼叫。
2. 最好一次把資料準備好再一次做function call處理,減少iteration。
3. jQuery loop最好把需要重複做"一樣"select的結果保存下來,避免重複做select動作。

2012年5月20日 星期日

Cross-domain Ajax: Implementation and Considerations

http://msdn.microsoft.com/zh-tw/magazine/gg624360(en-us).aspx

javascript由於安全性限制,跨站抓取資料一般而言是不可行的。想要達到Cross domain的資料交換,這裡舉出了一些可行的作法。

1. 利用代理伺服器方式取得
2. 利用<script>方式,引入外部網址script,並將資料用json方式包覆
3. flash或silverlight第三方元件
4. 還不成熟的CORS(Cross-Origin Resource Sharing)標準

基本上作者是建議用2以滿足現階段的環境使用啦。

2012年5月17日 星期四

JavaScript Attack/Defend

http://msdn.microsoft.com/zh-tw/magazine/hh243615(en-us).aspx

對於幹壞事而言一直有莫名的動力在。XSS出來很久了,我也一直努力想辦法在我們device裡面進行XSS攻擊。現在為止還沒有成功。現在卡在可動用字串長度太短。

防禦方式就從js與server端的檢查下手。

對於XSS更容易了解的範例,可以看XSS(Cross Site Scripting)攻擊會讓您遺失Cookie中的資料

2012年5月16日 星期三

How to Debug Your jQuery Code

http://msdn.microsoft.com/en-us/magazine/ee819093.aspx

這篇文章很清楚的描述了如何去利用Firebug及一些plugin套件去對jQuery的script作debug,非常有用。

大綱項目如下
1. FireBug
2. FireQuery
3. FireFinder
4. JQuery Trace插件使用
5. 使用中斷點察看js
6. 查看event原始觸發者
7. 查看事件觸發堆疊 (console.group, console.groupEnd)
8. 計算程式區塊執行時間 (console.time, console.timeEnd)
9. 查看json與ajax溝通
10. 使用條件式中斷

另外也推薦jsbin作為javascript沙盒的快速產生預覽,這樣就不用辛苦的寫測試html了。

2012年5月4日 星期五

c使用regular expression提取字串

在石頭閒語的"在 C 程式中,使用 Regex (Regular Expression) library" http://blog.roodo.com/rocksaying/archives/3866523.html 看到,試著編譯一下,挺實用的。

特地引用原始碼,以後會用到。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>

int main() {
regex_t preg;
regmatch_t pmatch[10];
size_t nmatch = 10;
int cflags = REG_EXTENDED | REG_ICASE;
int i, len, rc;
char buf[1024], reg[256], str[256];

while(1) {
printf("Input exp: ");
fgets(reg, 256, stdin);
if(reg[0] == '\n') break;
strtok(reg,"\n");

printf("Input str: ");
fgets(str,256,stdin);
if(str[0] == '\n') break;
strtok(str,"\n");

if( regcomp(&preg, reg, cflags) != 0 ) {
puts("regex compile error!\n");
return 1;
}

rc = regexec(&preg, str, nmatch, pmatch, 0);
regfree(&preg);

if (rc != 0) {
printf("no match\n");
continue;
}

for (i = 0; i < nmatch && pmatch[i].rm_so >= 0; ++i) {
len = pmatch[i].rm_eo - pmatch[i].rm_so;
strncpy(buf, str + pmatch[i].rm_so, len);
buf[len] = '\0';
printf("sub pattern %d is %s\n", i, buf);
}
}

return 0;
}

2012年4月24日 星期二

because 日傘

http://because.shop-pro.jp/

偶然看到的品牌,很有質感。一隻約2000日幣。在台灣撐吹爆很心疼吧!