curl -b cookie.txt -c cookie.txt http://blog.dasomoli.org/
curl -b cookie.txt -c cookie.txt http://blog.dasomoli.org/
일단 기본 개념부터.
PSK는 Pre-Shared Key의 줄임말로, 보안이 필요한 통신을 하는 양자 간에 미리 공유된 symmetric 키를 말한다.
TLS는 Transport Layer Security의 줄임말로, SSL이 표준화되면서 쓰이는 이름이다.
TLS-PSK는 PSK를 이용해서 TLS연결을 맺는 것으로 RFC 4279에 문서화되어 있다.
RFC 4279의 내용을 살펴보자.
Client Server ------ ------ ClientHello --------> ServerHello (Certificate) ServerKeyExchange* (CertificateRequest) <-------- ServerHelloDone (Certificate) ClientKeyExchange (CertificateVerify) ChangeCipherSpec Finished --------> ChangeCipherSpec <-------- Finished Application Data <-------> Application Data
위 그림이 TLS handshake과정을 나타낸다.
1. 클라이언트는 ClientHello 메시지에 TLS Version과 하나 이상의 cipher-suite을 실어 보낸다.
2. 서버는 ServerHello 메시지에 사용할 TLS Version과 사용할 cipher-suite를 실어 보낸다. ServerKeyExchange 메시지로 클라이언트가 어떤 PSK를 사용할 지, PSK identity hint를 함께 보낸다. ServerHelloDone도 보낸다.
3. 클라이언트는 ServerKeyExchange에 포함된 PSK identity hint로 사용할 PSK를 고른다. 고른 PSK의 PSK identity를 ClientKeyExchange 메시지에 실어 보낸다. Premaster secret은 PSK가 N octets라면, uint16 타입의 N, N개의 0 octets, 두번째 uint16타입의 N, 그리고 PSK N octets.
OpenSSL에서는 Client 쪽에서는 PSK callback을 SSL_CTX_set_psk_client_callback()이나 SSL_set_psk_client_callback()을 통해 설정하도록 되어있는데, 이 callback을 Server로부터 받은 PSK Identity Hint를 읽어 valid한지를 check하고, 해당 hint에 맞는 PSK를 psk에, PSK identity를 identity argument에 채워주는 역할을 한다. callback은 psk의 length를 return해야 한다. 0이나 그 이하는 error를 나타낸다.
Server쪽에서는 SSL_CTX_use_psk_identity_hint()나 SSL_use_psk_identity_hint()를 통해서 사용할 PSK Identity Hint를 Setting하고, SSL_CTX_set_psk_server_callback()나 SSL_set_psk_server_callback()을 통해 callback을 셋팅한다. 이 callback은 PSK identity가 valid한지를 체크하고, PSK identity가 있다면, pre-shared key를 psk argument에 채우고, PSK의 길이를 return한다.
* 참고
RFC 4279 – PSK Ciphersuites for TLS(https://tools.ietf.org/html/rfc4279)
TLS: https://en.wikipedia.org/wiki/Transport_Layer_Security, https://namu.wiki/w/TLS
TLS-PSK: https://en.wikipedia.org/wiki/TLS-PSK
OpenSSL
SSL_CTX_set_psk_client_callback: https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_set_psk_client_callback.html
SSL_CTX_use_psk_identity_hint: https://www.openssl.org/docs/manmaster/ssl/SSL_CTX_use_psk_identity_hint.html
#pragma pack(push, 1)
#pragma pack(pop)
OpenSSH가 7.0이상이면, 요 키 교환 알고리즘이 기본으로 켜져 있지 않아서 나는 문제인데, 다음과 같은 방법으로 해결 가능하다.
이걸 명령 줄 때마다 하긴 귀찮으니까 ~/.ssh/config 파일 안에 다음 내용을 추가하면 된다.
String copying
ssize_t strscpy(char *dest, const char *src, size_t count);
ssize_t strscpy_truncate(char *dest, const char *src, size_t count);
strscpy()는 src에서 dest로 최대 count bytes를 copy한다. source string이 count bytes보다 긴 경우를 제외하고는 copy된 bytes 수를 리턴한다. 긴 경우는 -E2BIG을 리턴한다. 다른 차이는 overflow 나는 경우는 src를 truncate하는게 아니라 dest가 empty string이 된다. 에러 체크를 항상 하면 괜찮은데, 안하는 경우, truncate된 string이 문제를 일으키는 일이 많기 때문에 이렇게 동작한다고 한다.
truncate된 string이 필요한 경우는 아래 버전을 사용하면 된다. 리턴 값은 같지만, null-terminate된 truncate된 string이 dest에 들어간다.
Integer parsing
simple_strto*() 함수가 많이 사용되지만, checkpatch가 불평하듯, kstrto*()가 더 낫다. 그런데, simple_strto*()는 “123abc”와 같은 string을 123으로 변환하는데, 이게 편리한 경우도 있다. 그래서 새로운 함수가 제안되었다.
int parse_integer(const char *s, unsigned int base, <type> *val);
사실, parse_integer()는 함수가 아니라 val의 타입에 맞는 여러가지 매크로이다. val이 unsigned short라면, 디코딩은 unsigned를 기초로 하고, 결과값이 short의 범위를 벗어나지 않는지 확인된다.
최종 결과는 val안에 담기고, 디코딩된 char 수가 리턴된다. 전체 string이 decode됐는지는 s[return_value] 가 null byte인지를 체크하면 된다. null-terminate string이면 원래 s[strlen(s)]는 ‘\0’일 테니까. 아니라면, 그 곳에 parsing하는 string이 계속 있을 거다. base가 문서화되지 않은 값 PARSE_INTEGER_NEWLINE과 or되면, 맨 마지막의 newline character는 무시-sysfs file로의 input을 parsing할 때 유용하다-된다. 아무 character도 convert되지 않으면, -EINVAL을 리턴한다. overflow인 경우 -ERANGE를 리턴한다.
출처: Improving kernel string handling(http://lwn.net/Articles/643376/)
[번역] 구글의 파이썬 튜토리얼 요약.
원문은 Google’s Python Class(https://developers.google.com/edu/python/)
* Python 환경 설정
나올 때 윈도우에서는 Ctrl-Z, 다른 OS에서는 Ctrl-D
* Introduction
if __name__ == ‘__main__’:
main()
sys.argv[0]는 프로그램 이름, sys.argv[1]은 첫번째 인자, sys.argv[2]는 두번째 인자…
TAB 문자 대신 Space들을 입력.
help(len) : len 함수에 대한 문서를 출력
dir(sys): sys 모듈에 대한 전반적인 문서
help(sys.exit): sys 내의 exit() 함수에 대한 문서
* Strings
파이썬 스트링은 “immutable”하다. 즉, 생성 후에 값을 변경할 수 없다. 따라서 다른 값이 되면 새로운 스트링이 생성된다.
“”” 로 여러줄 string 가능
[ ]로 문자 접근 가능
Slice로 substring 얻기
len(string) 은 string의 길이. sequence 타입에는 다 사용 가능
‘+’ 로 concatenate.
Value를 string 으로 변경하고 싶을 때는 str() 함수를 사용
pi = 3.14
text = ‘The value of pi is ‘ + str(pi)
정수로 나눗셈을 할 때는 // 를 사용. 6 // 5 == 1
print 뒤에 줄바꿈을 하고 싶지 않으면 마지막에 , 를 붙인다.
r 을 앞에 붙이면 ‘raw’ string. \ 를 특별히 취급하지 않는다. r’x\nx’ 는 ‘x\nx’ 가 됨. u 를 앞에 붙이면 unicode.
s.lower(), s.upper(): 소문자, 대문자로
s.strip(): 앞 뒤의 whitespace 제거
s.isalpha() / s.isdigit() / s.isspace(): 알파벳인지, 숫자인지, space인지
s.startswith(‘other’), s.endswith(‘other’): s 스트링이 다른 특정 스트링으로 시작하거나 끝나는지.
s.find(‘other’): s 스트링 안의 다른 스트링을 찾는다. 찾으면 인덱스 리턴, 못찾으면 -1
s.replace(‘old’, ‘new’): 모든 ‘old’를 ‘new’로 변경한 string 리턴
s.split(‘delim’): 주어진 delimiter로 자른 substring 리스트를 리턴,
s.join(list): split()의 반대, s를 delimiter로 리스트를 합친다.
길이가 1인 string 에 ==, <= 등의 작업을 할 수 있다. char 타입이 따로 없다.
H e l l o
0 1 2 3 4
-5 -4 -3 -2 -1
s[1:4]는 ‘ell’, s[1:]는 ‘ello’, s[:]는 ‘Hello’의 복사본, s[1:100]은 ‘ello’ – 더 큰 index를 사용하면 string의 length나 마찬가지가 된다.
s[-1]은 ‘o’, s[-4]은 ‘e’, s[:-3]은 ‘He’, s[-3:]은 ‘llo’
s[:n] + s[n:] == s 는 항상 참. n이 음수거나, index영역을 벗어났을 때도 성립.
% 연산자를 사용해 printf 같은 format string. %d는 int, %s는 string, %f/%g는 float, 오른쪽에 튜플.
text = “%d little pigs come out or I’ll %s and %s and %s” % (3, ‘huff’, ‘puff’, ‘blow down’)
너무 길면 전체 expression을 괄호로 싸면 된다.
text = (“%d little pigs come out or I’ll %s and %s and %s” %
(3, ‘huff’, ‘puff’, ‘blow down’))
unistring.encode()와 unicode로 encoding 변환.
s = unistring.encode(‘utf-8’)
t = unicode(s, ‘utf-8’)
t == unistring
if / elif/ else. “zero” 값들(None, 0, “”, ”, [], {}, False)은 false, True/False로 boolean 값, and, or, not 사용. ()로 expression 을 감싸지 않는다.
* Lists
= 을 사용하면 그냥 reference.
‘+’ 를 사용해 list를 합칠 수 있다.
for와 in 으로 iteration
squares = [1, 4, 9, 16]
sum = 0
for num in squares:
sum += num
print sum ## 30
in 은 독립적으로 어떤 원소가 list(또는 다른 collection)에 있는지 테스트 할 수 있다.
list = [‘larry’, ‘curly’, ‘moe’]
if ‘curly’ in list:
print ‘yay’
range(n)은 0, 1, 2, …, n-1 까지의 숫자를 리턴. range(a, b) 는 a, a+1, a+2, …, b-1 까지를 리턴.
for i in range(100):
print i
xrange()는 전체 리스트를 만드는 과정을 없애 성능 상 좋다.
while
i = 0
while i < len(a):
print a[i]
i = i + 3
list.append(elem): 리스트를 수정하여 가장 뒤에 elem 추가. 리턴하지 않는다.
list.insert(index, elem): index에 elem을 추가. 리턴하지 않는다.
list.extend(list2): list2의 원소들을 list에 추가. 리턴하지 않는다.
list.index(elem): elem이 있으면 index 리턴, 없으면 ValueError를 발생. ValueError 없이 확인하려면 in 을 사용.
list.remove(elem): 첫번째 elem을 제거, 없으면 ValueError. 리턴하지 않는다.
list.sort(): list를 sort. 리턴하지 않는다. sorted()를 더 자주 사용.
list.reverse(): list를 역순으로 변경. 리턴하지 않는다.
list.pop(index): index의 원소를 제거하고 리턴. index를 생략하면 가장 끝의 원소를 리턴(append()와 반대)
* Sorting
sorted()를 사용. reverse=True를 전달하면 역순. Case sensitive하다.
strs = [‘aa’, ‘BB’, ‘zz’, ‘CC’]
print sorted(strs) ## [‘BB’, ‘CC’, ‘aa’, ‘zz’]
print sorted(strs, reverse=True) ## [‘zz’, ‘aa’, ‘CC’, ‘BB’]
key로 함수를 전달하면 해당 함수를 key로 정렬. key=len, key=str.lower 하면 대소문자 동일하게 취급하여 정렬.
print sorted(strs, key=str.lower) ## [‘aa’, ‘BB’, ‘CC’, ‘zz’]
key로 custom 함수 전달 가능
def MyFn(s):
return s[-1]
print sorted(strs, key=MyFn)
cmp=cmpFn 선택 인자를 전달할 수도 있음. 내장 함수는 cmp(a, b)로 -/0/+ 로 순서를 리턴
Tuple은 struct와 비슷한 역할. 변경 불가능, 크기가 변하지 않음. () 를 통해 만듦. 크기가 1인 튜플은 ( 1, ) 처럼 , 을 넣어 만듦.
변수 할당에 사용 가능. 반환값이 여러 값을 가진 경우도 사용 가능
(x, y, z) = (42, 13, “Hike”)
(err_string, err_code) = foo()
[ _expr_ for var in list ] 형태로 원하는 형태의 리스트 생성 가능.
fruits = [‘apple’, ‘cherry’, ‘banana’, ‘lemon’]
afruits = [ s.upper() for s in fruits if ‘a’ in s ] ## [‘APPLE’, ‘BANANA’]
* Dictionaries and Files
dict = {}
dict[‘a’] = ‘alpha’
dict[‘g’] = ‘gamma’
dict[‘o’] = ‘omega’
print dict[‘a’] ## ‘alpha’
dict[‘a’] = 6
‘a’ in dict ## True
## print dict[‘z’] ## Throws KeyError
if ‘z’ in dict: print dict[‘z’] ## KeyError를 피한다.
print dict.get(‘z’) ## None
dict.get(key, not-found) 형태로 키가 없을 경우 not-found 로 설정한 값을 리턴하도록 할 수도 있다.
dict.keys(): key 리스트
dict.values(): value 리스트
dict.items(): (key, value) 튜플의 리스트
for k, v in dict.items(): print k, ‘>’, v
iterkeys(), itervalues(), iteritems()는 전체 리스트를 만들지 않아 성능 상 좋다.
hash = {}
hash[‘word’] = ‘garfield’
hash[‘count’] = 42
s = ‘I want %(count)d copies of %(word)s’ % hash # ‘I want 42 copies of garfield’
del 로 변수, list 원소, dict key/value를 지울 수 있다.
Files open(), close(). open 시 ‘rU’를 사용하면 줄바꿈을 ‘\n’으로 변형하여 준다.
f = open(‘foo.txt’,’rU’)
for line in f: ## 파일을 한 줄씩 방문
print line, ## line 끝에 이미 줄바꿈이 포함되어 있으므로 print가 줄바꿈하지 않도록 한다.
f.close()
f.readlines()는 전체를 메모리에 올리고 줄들의 list를 리턴, read()는 전체 파일을 하나의 string으로.
파일에 쓰려면, f.write(string). print를 사용하려면, print >> f, string. python 3에서는 print(string, file=f)
codes는 unicode를 읽을 때 사용 가능
import codecs
f = codecs.open(‘foo.txt’, ‘rU’, ‘utf-8’)
for line in f: # line은 unicode string이 됨.
* Regular expression
import re
str = ‘an example word:cat!!’
match = re.search(r’word:\w\w\w’, str)
if match:
print ‘검색 성공’, match.group() ## 발견 word:cat
else
print ‘검색 실패’
패턴 스트링은 항상 r로 시작.
a, X, 9: 있는 그대로의 문자를 매치
.: 아무 문자 하나를 매치. \n 은 제외
\w: 하나의 word에 쓰이는 문자 하나를 매치(단어가 아님). a-z, A-Z, 0-9, _ [a-zA-Z0-9_]를 매치.
\W: non-word에 쓰이는 문자 하나를 매치
\b: word와 non-word의 경계
\s: 하나의 whitespace 문자[ \n\r\t\f]를 매치
\S: whitespace 이외의 문자를 매치
\d: 숫자 [0-9]
^: 시작
$: 끝
\를 붙여 위의 것들을 그저 문자로 사용 가능
+: 왼쪽 패턴 1개 이상.
*: 왼쪽 패턴 0개 이상.
?: 왼쪽 패턴 0개 혹은 1개
+와 *는 가장 왼쪽의 것을 찾고, greedy 하다.
r'[\w.-]+@[\w.-]+’ 로 @ 주위에 ‘.’와 ‘-‘도 매치하도록 할 수 있다. -가 구간을 매치하지 않도록 하려면 가장 마지막에 넣는다.
[] 안의 내용을 ^로 시작하면 집합을 뒤집는다. [^ab]는 ‘a’와 ‘b’를 제외한 모든 문자를 뜻한다.
패턴 안에 ( )를 넣으면 그룹으로 구분할 수 있게 해준다.
str = ‘purple alice-b@google.com monkey dishwasher’
match = re.search(r'([\w.-]+)@([\w.-]+)’, str)
if match
print match.group() ## ‘alice-b@google.com’
print match.group(1) ## ‘alice-b’
print match.group(2) ## ‘google.com’
findall(): 모든 패턴에 해당하는 string 리스트를 리턴
f = open(‘text.txt’, ‘r’)
strings = re.findall(r’some pattern’, f.read())
findall 에 ( )를 넣으면 그룹에 해당하는 튜플 리스트를 만든다.
str = ‘purple alice@google.com, blah monkey bob@abc.com blah dishwasher’
tuples = re.findall(r'(\w\.-]+)@([\w\.-]+)’, str)
print tuples ## [(‘alice’, ‘google.com’), (‘bob’, ‘abc.com’)]
for tuple in tuples:
print tuple[0] ## username
print tuple[1] ## host
re.search(pat, str, re.IGNORECASE) 처럼 추가 옵션 가능
IGNORECASE: 대소문자 구별하지 않음
DOTALL: 마침표 . 이 newline을 매치하도록 한다. 보통은 newline을 제외한 모든것들을 매치.
MULTILINE: 여러줄로 이루어진 string에서 ^와 $가 줄의 시작과 끝을 매치하도록 한다. 보통은 ^ $는 전체 스트링의 시작과 끝을 매치한다.
정규 표현식의 확장으로 .*? 나 .+?처럼 ?를 끝에 더해서 greedy 하지 않게 변경할 수 있다.
str = ‘<b>foo</b> and <i>so on</i>’
match = re.search(r'(<.*>)’, str)
if match:
print match.group() ##'<b>foo</b> and <i>so on</i>’
match = re.search(r'(<.*?>)’, str)
if match:
print match.group() ## ‘<b>’
re.sub(pat, replacement, str) 은 str에서 pat과 매치되는 모든 스트링들을 찾아 replacement로 치환한다. replacement 스트링은 \1, \2 를 이용하여 group(1), group(2)를 표현할 수 있다.
str = ‘purple alice@google.com, blah monkey bob@abc.com blah dishwasher’
print re.sub(r'([\w\.-]+)@([\w\.-]+)’, r’\1@yo-yo-dyne.com’, str)
# purple alice@yo-yo-dyne.com, blah monkey bob@yo-yo-dyne.com blah dishwasher
* Utilities
os 모듈
filenames = os.listdir(dir): dir에 있는 .과 ..을 제외한 파일이름들의 리스트, 절대경로가 아님.
os.path.join(dir, filename): filename과 dir을 합쳐서 path를 만든다.
os.path.abspath(path): path를 받아서 절대 경로를 리턴
os.path.dirname(path), os.path.basename(path): dir/foo/bar.html을 받아서 dirname ‘dir/foo’와 basename’bar.html’을 리턴
os.path.exists(path): path 가 존재하면 True를 리턴
os.mkdir(dir_path): dir 하나를 만든다.
os.makedirs(dir_path): dir_path를 만들기 위한 모든 디렉토리들을 만든다.
shutil.copy(source-path, dest-path): 파일을 복사한다. 복사될 디렉토리가 존재해야 한다.
commands 모듈: 외부 명령을 실행하고 결과물을 얻어옴.
(status, output) = commands.getstatusoutput(cmd): cmd를 실행하고 exit할 때까지 기다려서,
status int값과 output text를 tuple로 리턴한다. stdout과 stderr이 하나의 출력물로 합쳐져서 나타난다.
output = commands.getoutput(cmd): 위와 동일, status값을 받지 않는다는 것만 다름.
commands.getstatus() 라는 함수는 사용하지 말아라.
sub-process에 대한 더 많은 제어권을 원하면 “popen2” 모듈을 보라.
os.system(cmd): cmd의 결과물을 여러분 코드의 output으로 출력하고, error 코드를 리턴.
try/except. ‘except IOError, e:’ 의 형태로 exception 객체에 대한 포인터를 얻을 수 있다.
try:
f = open(filename, ‘rU’)
text = f.read()
f.close()
except IOError:
sys.stderr.write(‘problem reading:’ + filename)
urllib 모듈: url을 마치 file처럼 읽을 수 있게 한다. urlparse 모듈은 url을 분해하거나 합치는 기능을 제공
ufile = urllib.urlopen(url): url에 대한 file 같은 객체를 리턴
text = ufile.read(): 파일처럼 읽음. readlines()도 사용 가능
info = ufile.info(): 요청에 대한 meta 정보를 리턴. info.gettype() 으로 ‘text/html’ 같은 mime 타입을 얻어 옴.
baseurl = ufile.geturl(): 요청에 대한 “base” url을 얻어옴. redirect로 인해 open할 때 사용한 url과 다를 수 있다.
urllib.urlretrieve(url, filename): url의 데이터를 다운받아 filename의 file로 저장한다.
urlparse.urljoin(baseurl, url): full url을 만든다.
def wget2(url):
try:
ufile.urllib.urlopen(url)
if ufile.info().gettype() == ‘text/html’:
print ufile.read()
except IOError:
prit ‘problem reading url:’, url
이전 설치 시 삽질을 많이 했었는데, 지금은 웹 상에 작성된 놓은 한글 가이드 문서가 있다.
Gerrit 코드리뷰(Code Review) 설치 가이드 1부 – 준비
Gerrit 코드리뷰(Code Review) 설치 가이드 2부 – Http 인증 설정
Gerrit 코드리뷰(Code Review) 설치 가이드 3부 – Gerrit 설치
Gerrit 코드리뷰(Code Review) 설치 가이드 4부 – Gerrit 설정
내가 정리했던 문서는 오래되기도 했고, 부끄러워 못 내놓겠다. ㅋ
ARM Cortex-A 페이징에 대해서 잘 적혀있는 글 발견!
설명하면서 쓴 단어의 정의들도 정확하다. 설명도 간략하면서 쉽게 되어 있다.
http://kth3321.blogspot.kr/search?q=ARM+Cortex-A+%ED%8E%98%EC%9D%B4%EC%A7%95
아참, 본문의 내용 중 예제에 Offset에 따른 물리 주소를 그저 Offset을 더하는 것으로 설명되어져 있는데, 이 부분은 잘못된 것으로 보인다. 실제로는 32비트 주소 값 혹은 pgd/pte 의 주소+a를 갖고 있으므로 Base + Offset * 4(=32 bits) 의 물리 주소를 참조한다.