2010年1月4日 星期一

ubuntu package - bind9-host


host主要拿來作DNS的lookup,和nslookup一樣,可以作正解(lookup/由domain name找到IP),也可以作反解(reverse lookup/由IP找到domain name),大多數的User比較常接觸到的是正解。
brook@ubuntu:~$ host dns.hinet.net
dns.hinet.net has address 168.95.1.1
brook@ubuntu:~$ 
brook@ubuntu:~$ host 168.95.1.1
1.1.95.168.in-addr.arpa domain name pointer dns.hinet.net.
brook@ubuntu:~$ 
brook@ubuntu:~$ host www.google.com
www.google.com is an alias for www.l.google.com.
www.l.google.com has address 72.14.203.99
www.l.google.com has address 72.14.203.147
www.l.google.com has address 72.14.203.104
www.l.google.com has address 72.14.203.103
www.l.google.com has address 72.14.203.105
www.l.google.com has address 72.14.203.106
brook@ubuntu:~$ 
brook@ubuntu:~$ host 72.14.203.99
99.203.14.72.in-addr.arpa domain name pointer tx-in-f99.1e100.net.

建議參考資料︰
  http://linux.vbird.org/linux_server/0350dns.php
  http://plog.longwin.com.tw/news_security/2005/11/06/dns_error_top_3

2010年1月3日 星期日

Linux Kernel(8)- Notification


Kernel提供一個notifiers/notifier chains的機制,這是publish-and-subscribe的機制,也就是需要的人自己去訂閱(join到某個notifier chain中),當這個chain的provider有事件要發布,就publish出來(發布給join這個chain的所有人)。
kernel中也提供了一些notifier,如reboot,可以透過register_reboot_notifier()訂閱,用unregister_reboot_notifier()取消訂閱。我們也可以自訂自己的notifier,以下例子就是自訂一個notifier。此一範例為透過寫入/proc/brook_notifier將資料publish給訂閱brook_notifier_list的scbscriber

notifier publisher
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

#include "notifier.h"

MODULE_LICENSE("GPL");
// 宣告一個新的notifier list – brook_notifier_list
BLOCKING_NOTIFIER_HEAD(brook_notifier_list);

// 訂閱brook_notifier_list事件的wrapper function
int register_brook_notifier(struct notifier_block *nb)
{
    return blocking_notifier_chain_register(&brook_notifier_list, nb);
}
EXPORT_SYMBOL(register_brook_notifier);

// 取消訂閱brook_notifier_list事件的wrapper function
int unregister_brook_notifier(struct notifier_block *nb)
{
    return blocking_notifier_chain_unregister(&brook_notifier_list, nb);
}
EXPORT_SYMBOL(unregister_brook_notifier);

// procfs的write function
static int write_proc(struct file *filp, const char __user *buf,
                               unsigned long count, void *data)
{
    char *p = kzalloc(sizeof(char) * count, GFP_KERNEL);
    if (!p) {
        printk("no mem\n");
        return -ENOMEM;
    }
    if (copy_from_user(p, buf, count)) {
        printk("fault\n");
        return -EFAULT;
    }
    printk("%s(): msg=\"%s\"\n", __FUNCTION__, p);

    // 將事件published給brook_notifier_list的subscriber
    blocking_notifier_call_chain(&brook_notifier_list, brook_num1, (void*)p);
    kfree(p);
    return count;
}

static int __init init_modules(void)
{
    struct proc_dir_entry *ent;

    ent = create_proc_entry("brook_notifier", S_IFREG | S_IWUSR, NULL);
    if (!ent) {
        printk("create proc child failed\n");
    } else {
        ent->write_proc = write_proc;
    }
    return 0;
}

static void __exit exit_modules(void)
{
    remove_proc_entry("brook_notifier", NULL);
}

module_init(init_modules);
module_exit(exit_modules);


notifier subscriber
#include <linux/init.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/notifier.h>

#include "notifier.h"

MODULE_LICENSE("GPL");

// callback function, 當brook_notifier_list有事件發生時, 會呼叫該function
static int brook_notify_sys(struct notifier_block *this,
                            unsigned long code, void *data)
{
    printk("%s(): code=%ld, msg=\"%s\"\n", __FUNCTION__, code, (char*)data);
    return 0;
}

// 宣告要註冊到brook_notifier_list的struct
static struct notifier_block brook_notifier = {
        .notifier_call =    brook_notify_sys,
};

static int __init init_modules(void)
{
    // 將brook_notifier註冊到brook_notifier_list
    register_brook_notifier(&brook_notifier);
    return 0;
}

static void __exit exit_modules(void)
{
    // 將brook_notifier自brook_notifier_list移除
    unregister_brook_notifier(&brook_notifier);
}

module_init(init_modules);
module_exit(exit_modules);


header file
#ifndef BROOK_NOTIFIER_H
#define BROOK_NOTIFIER_H

#include <linux/notifier.h>

int register_brook_notifier(struct notifier_block *nb);
int unregister_brook_notifier(struct notifier_block *nb);

// event type
enum brook_msg {
    brook_num1,
    brook_num2,
    brook_num3
};

#endif
基本上我們都透過notifier_chain_register()來訂閱某個notifier,透過notifier_chain_unregister()取消某個notifier的訂閱,用notifier_call_chain()來發布event,不過我們常常會用對訂閱與取消訂閱寫一層wrapper,如我們的register_brook_notifier()/unregister_brook_notifier()。



參考資料:



2009年12月27日 星期日

Linux Modules(7.2)- tasklet


Tasklet和timer類似(基本上都是運作在Softirqs上面),但是不同於timer會在特定時間執行,tasklet會在下一次interrupt來臨時執行。Tasklet有兩種implement,分別為TASKLET_SOFTIRQ和HI_SOFTIRQ,這兩種的差別在於HI_SOFTIRQ筆TASKLET_SOFTIRQ早執行。另外Tasklet只在註冊的CPU上面執行,而且註冊的tasklet同一時間只會被某個CPU執行。

您可以dynamically或statically的建立tasklet,
DECLARE_TASKLET(task, func, data);
DECLARE_TASKLET_DISABLED(task, func, data);

tasklet_init(task, func, data);

宣告後,還必須呼叫tasklet_schedule(task)才會被執行,但如果是用
DECLARE_TASKLET_DISABLED()宣告成disabled狀態,那就還必須用tasklet_enable()將其狀態設成enabled才能被執行。您也可以透過tasklet_disabled() disabled某個tasklet。tasklet_kill()可以保證tasklet不會被schedule,如果已經在執行,就會等它執行結束。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/slab.h>

MODULE_LICENSE("GPL");

static void f(unsigned long name);

// create tasklet statically
static DECLARE_TASKLET(t1, f, (unsigned long)"t1");
static DECLARE_TASKLET_DISABLED(t2, f, (unsigned long)"t2");

static struct tasklet_struct *t3;

static void f(unsigned long name)
{
    printk("%s(): on cpu %d\n", (char*)name, smp_processor_id());
}

static void f3(unsigned long name)
{
    static u32 c = 0;
    tasklet_schedule(t3);
    if (!(c++ % 2000000)) { // 每隔2000000次呼叫就印出訊息
        printk("%s(): on cpu %d\n", (char*)name, smp_processor_id());
    }
}

static int __init init_modules(void)
{
    // create tasklet dynamically
    t3 = kzalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
    tasklet_init(t3, f3, (unsigned long)"t3");

    tasklet_schedule(&t1);
    tasklet_schedule(&t2);
    tasklet_schedule(t3);
    tasklet_enable(&t2); // 沒有enable就不會被啟動
    return 0;
}

static void __exit exit_modules(void)
{
    // remove module就應該要確保tasklet有被移除
    tasklet_kill(&t1);
    tasklet_kill(&t2);
    tasklet_kill(t3);
}

module_init(init_modules);
module_exit(exit_modules);


Based on Kernel Version:2.6.35

參考資料:
Linux Kernel Development 3rd.
Linux Device Driver 3rd, http://www.makelinux.net/ldd3/chp-7-sect-5.shtml



熱門文章