顯示具有 Linux 標籤的文章。 顯示所有文章
顯示具有 Linux 標籤的文章。 顯示所有文章

2015/01/26

Linux 環境透過需要認證的 SMTP 寄信

近日同學公司的網頁找了一家新的設計公司設計,但是在留言板寄信功能出了點問題,如果寄到設計公司內部的信箱就可以收到,但是寄到同學公司的信箱會就收不到。最後發現是因為收信的信箱會對郵件來源進行網域反查,所以最終的解決方法是要真正登錄 SMTP 去寄發郵件,而不是單純 sendmail,所以寫這個筆記來記憶。

首先是 /etc/mail.rc 的設定,以下是簡單帳密登入的設定
set asksub append dot save crt=20
ignore Received Message-Id Resent-Message-Id Status Mail-From Return-Path Via
set from=寄件者信箱 smtp=寄件者的 SMTP 伺服器位址
set smtp-auth-user=登陸帳號 smtp-auth-password=登錄密碼
set smtp-auth=login
 
設定好了,那要怎麼寄信呢?在 shell 環境執行
echo "郵件內文" | mail -s "郵件主題" 收件者信箱

2014/04/03

[linux shell script] findgrep

[ "2" != "$#" ] && {
        echo "syntax:"
        echo "  $0 "'"filename" "greptext"'
        echo '          filename: like *.c or *.cpp'
        echo '          greptext: text you want to search.'
        echo "example:"
        echo "  $0 "'"*.c" "TODO:"'
} || {
        echo '[exec] find . -name "'$1'" | xargs grep "'$2'"'
        find . -name "$1" | xargs grep "$2"
}

2013/03/20

CentOS 5 編譯及安裝 freeRadius 2.2.0

使用 freeRadius,本文使用版本 2.2.0

以下使用 CentOS 5 環境,以 root 登入

下載原始碼

wget ftp://ftp.freeradius.org/pub/freeradius/freeradius-server-2.2.0.tar.gz

解包

tar xzvf freeradius-server-2.2.0.tar.gz

config

cd freeradius-server-2.2.0
./configure --prefix=/

編譯

make

安裝

make install

啟動 radius 服務

radiusd -X
參數 -X 表示要顯示除錯資訊,並會強迫為 foreground,第一次執行會先建立 EAP 相關的檔案,最好是使用 -X 執行,檢視有沒有意外狀況發生
之後執行只要執行 radiusd 就會以 daemon 的方式執行。

維護 /etc/raddb/clients.conf

原始的 localhost 設定,其中 secret 是這個 client 使用的通行碼。
client localhost {
    ipaddr = 127.0.0.1
    secret = testing123
    require_message_authenticator = no
    nastype = other
}
再來一個給實際使用的範例,172.20.3.1/24 通行碼為 octtelradius
client 172.20.3.1/24 {
    secret = octtelradius
    shortname = my-pool
}

維護 /etc/raddb/users

建立一個使用 pap 認證的 user
"octtel"        Auth-Type := pap, Cleartext-Password := "22635986"
                Reply-Message = "Welcome %{User-Name}."

測試

radtest octtel 22635986 172.20.3.202 1812 octtelradius
Sending Access-Request of id 20 to 172.20.3.202 port 1812
        User-Name = "octtel"
        User-Password = "22635986"
        NAS-IP-Address = 127.0.0.1
        NAS-Port = 1812
        Message-Authenticator = 0x00000000000000000000000000000000
rad_recv: Access-Accept packet from host 172.20.3.202 port 1812, id=20, length=37
        Reply-Message = "Welcome octtel."
密碼錯誤的測試
radtest octtel badpass 172.20.3.202 1812 octtelradius
Sending Access-Request of id 95 to 172.20.3.202 port 1812
        User-Name = "octtel"
        User-Password = "badpass"
        NAS-IP-Address = 127.0.0.1
        NAS-Port = 1812
        Message-Authenticator = 0x00000000000000000000000000000000
rad_recv: Access-Reject packet from host 172.20.3.202 port 1812, id=95, length=37
        Reply-Message = "Welcome octtel."
通行碼錯誤的測試
radtest octtel 22635986 172.20.3.202 1812 badsec
Sending Access-Request of id 78 to 172.20.3.202 port 1812
        User-Name = "octtel"
        User-Password = "22635986"
        NAS-IP-Address = 127.0.0.1
        NAS-Port = 1812
        Message-Authenticator = 0x00000000000000000000000000000000
Sending Access-Request of id 78 to 172.20.3.202 port 1812
        User-Name = "octtel"
        User-Password = "22635986"
        NAS-IP-Address = 127.0.0.1
        NAS-Port = 1812
        Message-Authenticator = 0x00000000000000000000000000000000
Sending Access-Request of id 78 to 172.20.3.202 port 1812
        User-Name = "octtel"
        User-Password = "22635986"
        NAS-IP-Address = 127.0.0.1
        NAS-Port = 1812
        Message-Authenticator = 0x00000000000000000000000000000000
radclient: no response from server for ID 78 socket 3

2013/01/28

Linux 的 contrack (使用 kernel 3.2)


一樣看 ipv4 的部份,hook 資訊在 ~/net/ipv4/netfilter/nf_contrack_l3proto_ipv4.c
static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
{
    .hookipv4_conntrack_in,
    .owner= THIS_MODULE,
    .pf= NFPROTO_IPV4,
    .hooknum= NF_INET_PRE_ROUTING,    PRE_ROUTING 會呼叫 ipv4_conntrack_in()
    .priority= NF_IP_PRI_CONNTRACK,
},{

    NF_INET_LOCAL_OUT 對應 ipv4_conntrack_local
},{
    NF_INET_POST_ROUTING 對應 ipv4_confirm
},{
    NF_INET_LOCAL_IN 對應 ipv4_confirm
}
ipv4_conntrack_in() {
    return nf_conntrack_in();    ~/net/netfilter/nf_conntrack_core.c
}
nf_conntrack_in() {
    if (skb->nfct) {    封包的 conntrack 存在表示這個封包是 loopbak 或是 (untarcked?),直接略過
    }
    l3proto = __nf_ct_l3proto_find();    ipv4 傳入 PF_INET,ipv6 傳入 PF_INET6,這樣作以後就可以支援更多的第三層協議
    ret = l3proto->get_l4proto();    取得第四層協議編號
    if (ret <= 0) {}    不認識的第四層協議就回報錯誤
    l4proto = __nf_ct_l4proto_find();    l4 協議實作程式在 ~/net/netfilter/nf_conntrack_proto_XXX.c
        例如:nf_conntrack_proto_tcp.c
        其 ipv4 的相關資料定義在 struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4
        其 ipv6 的相關資料定義在 struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6
    if (l4proto->error != NULL) {    有宣告說要檢查錯誤的協議,->error 指向錯誤檢查 function
        ret = l4proto->error();    檢查封包是不是正常
        if (ret <= 0) {}    檢查出錯誤就回報錯誤
    }
    ct = resolve_normal_ct();    依據 l3 跟 l4 的協議資料獲取 conntrack
    ret = l4proto->packet();    進行 l4 的 packet
    if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
        nf_conntrack_event_cache(IPCT_REPLY, ct);    設置 contrack event
}
resolve_normal_ct() {
    if (!nf_ct_get_tuple() {}    先把 tuple 找出來    hash = hash_conntrack_raw()    這兩行再把 hash 找出來
    h = __nf_conntrack_find_get()
    if (!h) {
        h = init_conntrack()    如果沒有找到 hash 就建立一個新的 hash
    }
    ct = nf_ct_tuplehash_to_ctrack(h);    把 hash 轉成 conntrack
    if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {
        方向是 Rep
    } else {
        方向是 Org,依據 ct->status 區分成三種狀態,ESTABLISHED、RELATED、NEW
    }    skb->nfct = &ct->ct_general;    這兩行將 ct 訊息回填 skb
    skb->nfctinfo = *ctinfo;
}
ipv4_conntrack_local() {    /* root is playing with raw sockets. */
    如果封包長度不符合 ip 的規定,那一定是 root 作 raw sockets 產生的
    return nf_conntrack_in()    呼叫 nf_conntrack_in
}
ipv4_confirm() {    ct = nf_ct_get(skb, &ctinfo);    取得 conntrack
    help = nfct_help(ct);
}

Linux 的 NAT (使用 kernel 3.2)


init: 以 ipv4 為例,初始化程式放置在 ~/net/ipv4/netfilter/nf_nat_rule.c
int __init nf_nat_rule_init(void)
      ret = xt_register_target(&ipt_snat_reg);    註冊 snat 的 target
      ret = xt_register_target(&ipt_dnat_reg);    註冊 dnat 的 target
static struct xt_target ipt_snat_reg __read_mostly = {
    .name= "SNAT",
    .targetipt_snat_target,
    .targetsize= sizeof(struct nf_nat_multi_range_compat),
    .table= "nat",        table: nat,iptables 裡面用 -t nat 來使用
    
.hooks= (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN),    只用到兩個 hook
    .checkentry= ipt_snat_checkentry,    指定規則檢查函數,同樣實做在 nf_nat_rule.c
    .family= AF_INET,
}    dnat 只有 .hooks 跟 .checkentry 不同
ipt_snat_target() {
    ct = nf_ct_get(skb, &ctinfo);    取得 conntrack 訊息
    /* Connection must be valid and new. */    作驗證
    return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC);
}
nf_nat_setup_info() {    實做在 ~/net/ipv4/netfilter/nf_nat_core.c
    struct nf_conntrack_tuple ...;    定義在 ~/include/net/netfilter/nf_conntrack_tuple.h,用來作連線識別
    nat = nfct_nat(ct);    從 conntrack 取出 nat 資訊
    if (!nat) {    如果沒有,就新增一個
        nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
    }
    nf_ct_invert_tuplepr(&curr_tuple, ...)    根據 reply 逆推當前的 tuple
    get_unique_tuple(&new_tuple, ...)    獲取作過 snat 之後的 tuple
    if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
        兩者不相等表示 tuple 發生變化了,要更新 conntrack 裡面 reply 的 tuple
    }
    if (maniptype == IP_NAT_MANIP_SRC) {
        第一次作 NAT 必須將 ORIGINAL 的 tuple 加入 hash 列表
    }
    /* It's done. */    打上 NAT 完成標記
}

2012/09/04

過濾 # 開頭及空白行

通常範例用的 .conf 都會有一堆註解,而我們只需要裡面幾行真正有用的,所以最好的方法就是把 org.conf 改成 new.conf.org 然後用指令把註解跟空白行刪掉。指令:


cat org.conf | sed 's/#.*$//g' | sed '/^$/d' > new.conf