網頁

2015年7月8日 星期三

[linux] add user

主題: 假設想要多個可信認的user共用一台機器,每個user有權限可以轉換身分到root


How to ?

1. 加入一般身分的user
2. 修改visudo

2015年7月6日 星期一

[Python] @staticmethod 和 @classmethod

主題: @staticmethod和@classmethod的差別

說明:

這兩個都是decorator,
一言以蔽之 classmethod的input function第一個參數必須是class,
而staticmethod則第一個參數就是真的參數。

可以參考這邊(staticmethod/classmethod)

另外一提,這兩個的實作方式和@property的做法很像。

[Python] __slots__ 記憶體優化工具

主題: __slots__

範例:



不使用__slots__優化記憶體(內部為一個hash table)
#!/usr/bin/python
from pympler import asizeof

class A(object):
        #__slots__ = ['year', 'month', 'day']
        def __init__(self, year, month, day):
                self.year = year
                self.month = month
                self.day = day

a = A(1,2,3)
print asizeof.asized(a, detail=1).format()
<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x7f15e50e9cd0="" data-blogger-escaped-at="" data-blogger-escaped-object=""> size=552 flat=64
    __dict__ size=488 flat=280
    __class__ size=0 flat=0
使用__slots__優化記憶體(不存table, 分開以更節省記憶體的方式存)
#!/usr/bin/python
from pympler import asizeof

class A(object):
        __slots__ = ['year', 'month', 'day']
        def __init__(self, year, month, day):
                self.year = year
                self.month = month
                self.day = day

a = A(1,2,3)
print asizeof.asized(a, detail=1).format()
<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x191f6c8="" data-blogger-escaped-at="" data-blogger-escaped-object=""> size=224 flat=72
    __slots__ size=80 flat=80
    month size=24 flat=24
    day size=24 flat=24
    year size=24 flat=24
    __class__ size=0 flat=0

結論:

使用__slots__優化記憶體 552->224
缺點就是因為內部不存hash table, 所以你也只能使用__slots__指定的那些屬性名稱

2015年7月5日 星期日

[Python] property繼承的寫法

主題: property繼承的寫法


假設我們有一個擁有name property的class A:

class A(object):
        def __init__(self):
                print ("A init")
        @property
        def name(self):
                print ("A name getter")
        @name.setter
        def name(self, x):
                print ("A name setter")
我們想要對A的name property繼承,並且改寫。 改寫的方式想要繼承A原本的一些code再附加新的class的一些code,可以這樣寫:
class B(A):
        def __init__(self):
                print ("B init")

        @property
        def name(self):
                super(B, B).name.fget(self)
                print ("B name getter")

        @name.setter
        def name(self, x):
                super(B, B).name.fset(self, x)
                print ("B name setter")

或者把fget和fset換成__get__和__set__
class B(A):
        def __init__(self):
                print ("B init")

        @property
        def name(self):
                super(B, B).name.__get__(self)
                print ("B name getter")

        @name.setter
        def name(self, x):
                super(B, B).name.__set__(self, x)
                print ("B name setter")

為什麼可以這樣? 有興趣的人可以去研究一下 property這個class

還有一點要注意, 其實這樣的寫法是"定義B的自己版本name property", 換句話說,
B.name和A.name是兩個不同的版本。
也就是如果B只有定義getter或是setter,那麼這個property也只會剩下getter或是setter的能力:


#!/usr/bin/python

class A(object):
        def __init__(self):
                print ("A init")
        @property
        def name(self):
                print ("A name getter")
        @name.setter
        def name(self, x):
                print ("A name setter")


class B(A):
        def __init__(self):
                print ("B init")

        @property
        def name(self):
                super(B, B).name.__get__(self)
                print ("B name getter")

b = B()
b.name
b.name = 3

結果:
B init
A name getter
B name getter
Traceback (most recent call last):
  File "./property.py", line 25, in 
    b.name = 3
AttributeError: can't set attribute

Shell 已返回1

結論:

1. child class要改寫parent class的property最好全部都改寫,除非你知道你在做什麼,你真的想閹割parent class的setter or getter or deleter ?
2. child class若要呼叫parent class的class method(memer data), 那就要用 super(B, B).name的寫法
3. property class有實作"descriptor protocol"(__get__, __set__, __delete__這三個function),
property class的__get__會去呼叫 property class的instance method: fget
property class的__set__會去呼叫 property class的instance method: fset
property class的__delete__會去呼叫 property class的instance method: fdel

2015年7月4日 星期六

[Python] decorator的等價寫法

主題: decorator的等價寫法


class A(object):
    @property
    def func(self):
       ...



class A(object):
    def func(self):
       ...
    func = property(func)

換句話說這時候 func經過property之後
1. 從單純的func變成為property
2. func則變為 class variable (不是intance variable)


[Python] property and descriptor protocol

主題: 了解property的概念

簡介: 

假設今天我們有一個需求,我們有一個A class:
a = A()
當寫 a.m 我們希望呼叫到 A.f
當寫 a.m = 3我們希望呼叫到 A.g
當寫 del a.m我們希望呼叫到A.p

那我們該如何實作 ?

答案在這邊 (直接參考property這個class的實作方式)

個人理解:

先說一下規則好了,如果一個有實作 "descriptor protocol"的class,假設叫D好了:
當寫 
d = D()
d  
d = 5
del d
則會觸發
__get__
__set__
__del__

據此,我們可以讓 __get__ 去呼叫A.f
__set__去呼叫A.g
__del__去呼叫A.p
就可以達到題目需求....

但這樣很不彈性,
因此我們再多寫三個function以便有機會可以替換掉
A.f
A.g
A.p

其實以上就是property的概念:
"
Property是一個class擁有fget, fset, fdel這三個function,
我們可以用 getter, setter, deleter去註冊這三個function,
且getter, setter, deleter回傳都是Proptery object。
"

2015年7月2日 星期四

[Python] 雙底線的用處

目的: 了解雙底線的用處

1. 不可繼承
2. public
3. 不管是class member或method都遵循這個規則

以下用class method舉例:
#!/usr/bin/python

class A(object):
        def __init__(self):
                pass

        def test1(self):
                print "test1"
        def __test2(self):
                print "test2"

class B(A):
        def __init__(self):
                pass

b = B()
b.test1()
b.__test2()
結果:(注意test1有印出來但呼叫__test2時發生AttributeError的Exception)
test1
Traceback (most recent call last):
  File "./private.py", line 18, in 
    b.__test2()
AttributeError: 'B' object has no attribute '__test2'

[Python] old style class vs new style class

目的: 了解什麼是old style class ? 什麼是 new style class ? 如何使用super ?


先看這篇 ,簡短的說明一下這篇內容好了:
1. class有繼承object這個class是new style class, 否則就是 old style class
2. old style class是for python 2.2以前的向下相容
3. python內建的繼承功能可以說是由 object class所提供

其中有一點很重要,就是super()功能是new style class的功能。

正規上如果B要繼承A且建構順序是先A再B, 我們就要用super()
super()的影響在多重繼承上會很明顯。
可以看這篇 

總結一下:
1. super()的用法是: 第一個參數是這個class名稱, 第二個參數是self
2. 執行順序有一套自己的演算法,可以想成parent class的__init__一定先執行:
#!/usr/bin/python

class A(object):
        def __init__(self):
                print ("[A]")

class A0(A):
        def __init__(self):
                super(A0, self).__init__()
                print ("[A0]")

class A1(A):
        def __init__(self):
                super(A1, self).__init__()
                print ("[A1]")

class A2(A):
        def __init__(self):
                super(A2, self).__init__()
                print ("[A2]")

class A21(A2):
        def __init__(self):
                super(A21, self).__init__()
                print ("[A21]")

class A22(A2):
        def __init__(self):
                super(A22, self).__init__()
                print ("[A22]")

class B(A1, A21, A22, A0):
        def __init__(self):
                super(B, self).__init__()

B()
結果: (所有class的__init__都被剛好執行一次, 且有parent/child繼承關係parent一定會比child先做)

[A]
[A0]
[A2]
[A22]
[A21]
[A1]

2015年7月1日 星期三

[Python][cook][269-269] with 語法

目的: 了解Python with語法

Python with的語法有點像是c++的scope,當進入with區間時, 會進入__enter__function, 當離開with區間時, 會先執行__exit__ function (即使with區間產生exception也會進__exit__)

範例1. __enter__ return自己


#!/usr/bin/python

class A:
        def __init__(self):
                print "__init__"

        def __enter__(self):
                print "__enter__"
                return self

        def __exit__(self, exc_ty, exc_val, tb):
                print "__exit__"

a = A()
with a:
        print " in with "

結果:

__init__
__enter__
 in with x=<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x7faa8553ac68="" data-blogger-escaped-at="" data-blogger-escaped-instance="">
__exit__

範例2. __enter__ 不return值

#!/usr/bin/python
class A:
        def __init__(self):
                print "__init__"

        def __enter__(self):
                print "__enter__"

        def __exit__(self, exc_ty, exc_val, tb):
                print "__exit__"

a = A()
with a as x:
        print " in with x=%r" % x

結果:

__init__
__enter__
 in with x=None
__exit__

範例3. __enter__ return另一個class的obj


#!/usr/bin/python
#!/usr/bin/python
class B:
        def __init__(self):
                pass

        def showB(self):
                print "This is B"

class A:
        def __init__(self):
                print "__init__"

        def __enter__(self):
                print "__enter__"
                return B()

        def __exit__(self, exc_ty, exc_val, tb):
                print "__exit__"

a = A()
with a as b:
        print " in with "
        b.showB()

結果:

__init__
__enter__
 in with
This is B
__exit__

範例4. with區間有raise Exception

#!/usr/bin/python
class A:
        def __init__(self):
                print "__init__"

        def __enter__(self):
                print "__enter__"
                return self

        def __exit__(self, exc_ty, exc_val, tb):
                print "__exit__ %r %r %r" % (exc_ty, exc_val, tb)

a = A()
with a as x:
        print " in with x=%r" % x
        raise Exception("exp1234")

結果: (可以看到__exit__仍有被執行且__exit__的參數有exception相關資訊)

__init__
__enter__
 in with x=<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x7f1c4bc0ac68="" data-blogger-escaped-at="" data-blogger-escaped-instance="">
__exit__  Exception('exp1234',) 
Traceback (most recent call last):
  File "./with.py", line 16, in 
    raise Exception("exp1234")
Exception: exp1234

[Python][Cook][265-266] 實作class 的 __str__, __repr__ 的效果

目的: 觀察實作__str__, __repr__的效果

實作前:

#!/usr/bin/python



class A:

        def __init__(self, x, y):

                self.x = x

                self.y = y



a = A(5, 6)

print a

print "%r" % a

print "{0!r}".format(a)

print str(a)

<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x7f433e42db48="" data-blogger-escaped-at="" data-blogger-escaped-instance="">
<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x7f433e42db48="" data-blogger-escaped-at="" data-blogger-escaped-instance="">
<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x7f433e42db48="" data-blogger-escaped-at="" data-blogger-escaped-instance="">
<__main__ data-blogger-escaped-.a="" data-blogger-escaped-0x7f433e42db48="" data-blogger-escaped-at="" data-blogger-escaped-instance="">

實作後:

#!/usr/bin/python



class A:

        def __init__(self, x, y):

                self.x = x

                self.y = y

        def __str__(self):

                return 'This is A __str__'

        def __repr__(self):

                return '<A __repr__>'



a = A(5, 6)

print a

print "%r" % a

print "{0!r}".format(a)

print "{0!s}".format(a)

print str(a)

This is A __str__
<A __repr__>
<A __repr__>
This is A __str__
This is A __str__

2015年6月28日 星期日

[Python] inspect.getargspec

主題: inspect.getargspec

Example:

#!/usr/bin/python

import inspect

def myfunc(a, b=2, c=1, *args, **kwargs):
        print ("%r %r %r" % (a,b,c))
        return a

argspec = inspect.getargspec(myfunc)

print (str(argspec))

結果:

ArgSpec(args=['a', 'b', 'c'], varargs='args', keywords='kwargs', defaults=(2, 1))

結論:

利用inspect.getargspec可以取得func的argument的相關資訊

[Python] bind

主題:想要對Python的function有bind的能力


簡介:

C++, javascript裡面都叫bind但在python則由functools的partial完成。

什麼是bind ?
就是"綁定", 綁定什麼 ? 讓你的func參數的parameter綁定某些值。

相信看完下面的範例就會有感覺

Example:

#!/usr/bin/python3

from functools import partial

def myfunc(x, y, z):
        print ("%r %r %r" % (x,y,z))

binded_myfunc = partial(myfunc, 2, 3, 4)

myfunc(1,2,3)

binded_myfunc()

結果:
1 2 3
2 3 4


[blog] code highlight

主題: 如何在google blog內貼code可以highlight ?


Ref: 主要還是要看這一篇 非常詳細。
簡述一下:
Step1: 在template內head前貼上javascript code
Step2: use it !
舉例來說如果是python code
<pre class="brush:python;">
...
</pre>

舉例來說如果是php code
<pre class="brush:php;">
...
</pre>

效果:
#!/usr/bin/python3

print ("This is python code")


2015年6月25日 星期四

[Python][Metaprogramming] 9.1 decorator

介紹@wraps decorator


沒加@wraps

<pre class='codeblock'>#!/usr/bin/python

import time
from functools import wraps

def timethis(func):
 '''
 Decorator that reports the excution time
 '''
 #@wraps(func)
 def wrapper(*args, **kwargs):
  start = time.time()
  result = func(*args, **kwargs)
  end = time.time()
  print(func.__name__, end-start)
  return result
 return wrapper

@timethis
def countdown(n):
 '''
 Counts down
 '''
 while n > 0:
  n -= 1


countdown(10000)
print countdown.__name__
print countdown.__doc__

<\pre>

結果:

'countdown', 0.00028896331787109375) 
wrapper
None

有加@wraps

結果:

('countdown', 0.00029587745666503906) 
countdown 
Counts down

結論:

寫decorator若想保留原來的funcion __name__, __doc__那就要加 @wraps
否則就會被替換成 wrapper, None

2015年5月6日 星期三

python decorator

只是筆記一下

目的:
假設我們想要對某些function的回傳值做一個簡單的處理:
如果回傳值昰list且指有一個元素就直接取出(不放在list裡面)

def unpack_list_for_one_item(fn):                                                                            
    "unpack list for one item, if fn return ['5.1'] than return '5.1'"                                        
    def decorator(*args, **kwargs):                                                                          
        fnRet = fn(*args, **kwargs)                                                                          
        if not isinstance(fnRet, list):                                                                      
            raise TypeError("The decorator-unpack_list_for_one_item input fn{0}'s result shall be list type".format(fn))                                                                                                      
                                                                                                             
        return fnRet[0] if 1==len(fnRet) else fnRet                                                          
    return decorator                                                                                          

用法:
    @unpack_list_for_one_item
    def major(self):      
       ....

    @unpack_list_for_one_item
    def minor(self):      
       ....

    @unpack_list_for_one_item
    def patPath(self):      
       ....

解說:
1. decorator如果沒有額外參數input和output都是function
2. decorator即使沒有被呼叫也會被run過(第一層),且在main之前就被run過,如下:
#!/usr/bin/python3

from functools import wraps, partial
import logging

def logged(func):
        print ("%r %s" % (locals(), "0"))
        def innerDecorate(*args, **kwargs):
                print ("%r %s" % (locals(), "1"))
                return func
        return innerDecorate

@logged
def add(x, y):
        return x + y


注意, add並沒有被呼叫, 但結果如下:
{'func': <function add at 0x7f6798c77170>} 0

這表示 print ("%r %s" % (locals(), "0")) 有被執行
並且注意 print ("%r %s" % (locals(), "1")) 沒有被執行

但注意我們只是對func加上decorator

那如果是有參數的decorator會如何?
#!/usr/bin/python3



from functools import wraps, partial

import logging





def logged(level, name=None, message=None):

        print ("%r %s" % (locals(), "0"))

        def decorate(func):

                logname =  name if name else func.__module__

                log = logging.getLogger(logname)

                logmsg = message if message else func.__name__

                print ("%r %s" % (locals(), "1"))



                @wraps(func)

                def wrapper(*args, **kwargs):

                        print ("%r %s" % (locals(), "2"))

                        log.log(level, logmsg)

                        return func(*args, **kwargs)



                return wrapper

        return decorate



@logged(logging.DEBUG)

def add(x, y):

        return x + y


注意,一樣add並沒有被呼叫, 但結果如下:
{'message': None, 'level': 10, 'name': None} 0
{'message': None, 'logmsg': 'add', 'func': <function add at 0x7f8c9f649710>, 'logname': '__main__', 'name': None, 'log': <logging.Logger object at 0x7f8c9f66db10>, 'level': 10} 1

這表示 print ("%r %s" % (locals(), "0")) / print ("%r %s" % (locals(), "1"))  有被執行
並且注意 print ("%r %s" % (locals(), "2")) 沒有被執行

2015年3月18日 星期三

如何在apache2設定php5

主題: 如何在apache2設定php5

環境: Ubuntu

目標: 網頁show出hello1

Commands:

1. create kkk.php
cd /var/www
mkdir cgi-bin
vim kkk.php
-----------------
<?php

echo "hello1";

?>

2.  確定有沒有libphp5.so
find / -name libphp5.so  -print

3. 如果沒有libphp5.so裝一個
apt-get install libapache2-mod-php5

4. 確定位置
find / -name libphp5.so -print
/usr/lib/apache2/modules/libphp5.so

5. 設定apache2.conf
vim /etc/apache2/apache2.conf
加入
-------------------------------------------
LoadModule php5_module  /usr/lib/apache2/modules/libphp5.so
AddType application/x-httpd-php5 .php

6. 重啟動apache2
apachectl restart

7. 正常的話
http://localhost/cgi-bin/kkk.php
會出現
hello1

2014年11月2日 星期日

[封包如何在子網域間流動 ?] subnet mask, network number, subnet mask

主題: 封包如何在子網域間流動 ?


環境:
     src:   10.13.20.127 (位於10.13.20.0 子網域下)
     dest:  10.13.18.54  (位於10.13.18.0的子網域下)
     subnet mask : 255.255.248.0


NOTE: 如果不記得 subnet設置方式的朋友可以先看 http://www.clyeh.org/ipsubnet/ipsubnet.htm 來複習一下。


主要的Policy:
    (ip & subnet mask) ===> network number
    network number必須在gateway的ip table上找到對應的interface

對就是上面兩句話就是子網域下傳送的方式


看一個範例好了

(src: 10.13.20.127, dest: 10.13.18.54) ---> gateway1

gateway1上面的routing table若是有

....
10.13.18.0  255.255.248.0  eth?
...
的record

那麼這個封包就會被傳送到 eth1,eth1一般會是10.13.18.0的gateway(gateway2)

因為10.13.18.54是gateway2下的一個node,gateway2自然就會把封包傳送到這一台node上

當然,當封包要回傳的時候就是相反的順序


換言之,gateway1和gateway2上面的routing table上要有互相的record封包發送的來回才不會出問題。

也就是 gateway2上面的routing table也要有
....
10.13.20.0  255.255.248.0  eth?
...
的record


結論: 雖然網域被切開了,但是封包的傳送只要routing table設定正確理論上都要可以正常的收發。

最後附上一張圖來表示這個概念:

NOTE: 也就是說穿就是一個將 dst ip 轉換成 interface的一個系統,當有一個dst ip,利用這樣的轉換就可以知道要送到哪個interface上,不管在 PC 、手機、switch、gateway、router上都會有一個這樣的系統,尤其一個有幾十個以上的interface的switch/gateway/router上這樣的routing table更是龐大。

NOTE: dst ip是input ,而ip mask/network number/interface則是是先先設定好的資訊(如何設定? 在linux/windows上可以查詢 'route' 這個指令)

2014年9月9日 星期二

有關FTP自動開port (hole punching)

問題:

Nessus偵測到的FTP server風險。
在同一個區網內的device皆可以借由ftp偷取ftp server上的資訊。

主要原因是因為FTP的protocol在加上router自動hole punching所造成的安全性風險。

環境:

A: ftp client (192.168.1.100)
A1: another ftp client (192.168.1.101)
B: ftp client's router
C: ftp server with public ip

流程:

A ---> B ---> C  (A送出ftp command: PORT ip:port)
C就會replay

在過程中B會因為看到 dst的 port為21 port,因此會偷改 PORT ip:port 為 PORT external_ip:random_port

因此在ftp server端是分辨不出來是否為同一個來源,只知道是在B之下的一個client。

因此 A1利用wireshark或是其他的軟體可以偽造一個 PORT 192.168.1.101:port的封包給 C,C分辨不出來,就會回資訊給B,B會忠實的再回給A1。A1就可以拿到別人的資料。

如何避免這個風險 ?
方法一: ftp server不要用21 port。但此時ftp client端的router要自己手動設portforwarding。
方法二: 使用安全的 tls + ftp 或 ftps,但perforamance會掉很多。

Reference:

https://wiki.filezilla-project.org/Network_Configuration#Malicious_routers.2C_firewalls_and_data_sabotage
http://tools.ietf.org/html/rfc2663
http://www.practicallynetworked.com/support/linksys_ftp_port.htm

2014年9月4日 星期四

[DNS] dynamic update

Dynamic update

環境:

開發機 (A)
裝DNS bind9的機器 (B)

在Zone data加入 allow-update 如下 (on B)

zone "test.com" {                      
        type master;                  
        file "/etc/zone/master/test.com";
        allow-transfer {any;};        
        allow-query {any;};            
        allow-update {any;};      <--- 以上三個設置都非常危險,這邊只是為了做實驗方便
};                                    

把rndc.key 從B copy到A (on B)

把record add到DNS Server (on A)

nsupdate -k rndc.key
> prereq yxdomain test.com
> update add trr123.test.com
> update add try123.test.com 300 A 192.253.253.16
> send

NOTE: 如果成功,可以看到 test.com.jnl會被產生出來

把.jnl file sync到zone file裡面 (on B)

針對test.com會自動sync並且砍.jnl file:
./rndc -k ../named/rndc.key sync -clean test.com也可以對全部的domain sync並砍掉所有的.jnl file
./rndc -k ../named/rndc.key sync -clean

NOTE: 這動作要定期做,以免.jnl的大小成長到超過2G。在很多平台上處理超過2G的file都會出問題。

參考資料:

http://docstore.mik.ua/orelly/networking_2ndEd/dns/ch10_02.htm
https://www.centos.bz/2012/05/bind-nsupdate-dynamic-dns-update-tool/
http://dns-learning.twnic.net.tw/bind/security.html
http://www.zytrax.com/books/dns/ch7/xfer.html#max-journal-size
ftp://ftp.isc.org/isc/bind/9.8.0-P4/doc/arm/Bv9ARM.ch04.html
http://serverfault.com/questions/560326/ddns-bind-and-leftover-jnl-files (最後一個post)

2014年9月2日 星期二

[login system] 如何實作 login system ?

環境:

A: Server (192.168.0.101) + Apache2 Server
B: Client (192.168.0.101) + browser

概念流程:

Cookie sid尚未存在於browser的情況 -

A  <--------------------------------------------- GET index.cgi -----------------------------------------  B
A  ---------------------------------------------- output login.html --------------------------------------> B
A  <------------------------------ POST username/passowrd  to login.cgi (js) -----------------------  B
A  -----after login.cgi response: write sid into cookie and then redirect to index.cgi (js)--------> B


Cookie sid存在browser的情況 -

A  <--------------------------------------------- GET index.cgi -----------------------------------------  B
A  ---------------------------------------------- output login.html --------------------------------------> B

index.cgi

if (COOKIE's sid in connected sessions) {
    output operation.html
} else {
    output login.html
}

login.cgi

if (username and password in db) {
    reponse sid for write cookie
} else {
    // do nothing
}

安全性考量:

1. user輸入的username和password都需要在client js端加密
2. 存下來的user/password一定要是加密後的結果

References:

一篇好文章,有關password加密入門基礎觀念
http://www.jasypt.org/howtoencryptuserpasswords.html

CGI programming
http://www.tutorialspoint.com/cplusplus/cpp_web_programming.htm

Http Cookie
http://en.wikipedia.org/wiki/HTTP_cookie

有關C/C++ key generate sample code(public key/private key)
https://shanetully.com/2012/04/simple-public-key-encryption-with-rsa-and-openssl/

有關javascript encrypt
https://code.google.com/p/crypto-js/#SHA-1