1.OpenStack虚拟机如何获取metadata
2.使ç¨å½ä»¤è¡å¯åHAProxyçBackend
3.HAProxy ç ACLs 详解
4.超级NB的黑科技,实现socket进程间迁移!
OpenStack虚拟机如何获取metadata
OpenStack虚拟机初始化配置主要依赖cloud-init,其通过Metadata服务获取配置信息。Metadata服务的配置包括Nova和Neutron的设置,如将metadata服务与nova-api合并,年会抽奖源码excel以及选择通过dhcp-agent转发。访问Metadata服务的地址为...,这是个保留的IPv4 Link Local Address,用于直连网络的内部通信。
OpenStack虚拟机通过访问...获取诸如uuid、name等信息,这个过程涉及三次转发:首先到DHCP地址,再由haproxy转发到一个本地socket文件,await源码介绍最后neutron-metadata-agent根据network id和IP信息确定虚拟机uuid。Nova Metadata服务通过uuid查询metadata信息,并在转发前验证secret以确保安全性。
在虚拟机外部获取metadata,可以通过Python脚本生成secret并利用它调用nova-api-metadata服务。整个流程涉及Nova Metadata服务、DHCP地址转发、本地socket文件处理和secret验证。
使ç¨å½ä»¤è¡å¯åHAProxyçBackend
HAProxyèªå¸¦çæ§é¡µé¢ï¼éè¦å¨HAProxy使ç¨çé ç½®æ件haproxy.cfgä¸æ·»å é 置项è¿è¡å¼å¯ï¼éå¯HAProxyæå¡åçæãæ·»å çé 置大è´å¦ä¸ï¼
æµè§å¨å°åæ è¾å ¥ t <integer>
req_rdp_cookie_cnt(name) <integer>
è¿ç¨æ¡é¢åè®®ç¸å ³
req_ssl_ver <decimal>
å¦æå¨è¯·æ±ç¼åä¸çæ°æ®ï¼çèµ·æ¥å SSL åè®®æ°æ®ï¼èä¸åè®®çæ¬å¨æå®çèå´å ï¼è¿å tureã
æ¯æ SSLv2 hello messages å SSLv3 messagesã
æ¤æµè¯æå¨è¿è¡ä¸¥æ ¼éå¶ï¼å°½éé¿å 被轻æå°æ¬ºéªã
In particular, it waits for as many bytes as announced in the
message header if this header looks valid (bound to the buffer size)
注æï¼TLSv1 åè®®å°è¢«ç§°ä¸º SSL version 3.1ã
ç¨äº âTCP 请æ±å 容æ£æ¥â
wait_end
çå¾ åæå¨æç»æï¼è¿å trueã
ä¸è¬ä¸å 容åæèå使ç¨ï¼é¿å è¿æ©è¿åä¸ä¸ªé误çç»è®ºã
ä¹å¯ç¨äºå»¶è¿æäºå¨ä½ï¼æ¯å¦æç»æäºæå®çIPå°åçå¨ä½ã
å 为å®è¦ä¹åæ¢è§åæ£æ¥ï¼è¦ä¹ç«å³è¿å trueï¼æ以建议å¨ä¸æ¡è§åçæå使ç¨è¿ä¸ª aclã
注æï¼é»è®¤ç ACL "WAIT_END" æ»æ¯å¯ç¨çï¼ä¸éè¦é¢å 声æã
æ¬æµè¯ç¨äº âTCP 请æ±å 容æ£æ¥â
示ä¾ï¼
第ä¸é¨åçæµè¯åºåï¼æ¯ä¸å±æµè¯ãè¦æ±å¯¹ HTTP 请æ±è¿è¡å®å ¨ç解æä¹åè¿è¡ã
å 为请æ±åååºé½è¢«å»ºç«äºç´¢å¼ï¼æ以è½ç¶ç¸æ¯åå±å¹é è¦æ±æ´å¤ç CPU èµæºï¼ä½ä¹ä¸ä¼å¤ªå¤ã
hdr <string>
hdr(header) <string>
hdr* å¹é ææ headersï¼hdr*(header) å¹é æå®ç headerï¼æ³¨ææ¬å·éé¢ä¸è½æç©ºæ ¼ã
æå®é¦é¨æ¶ï¼å ¶å称ä¸åºå大å°åï¼
The header matching complies with RFC, and treats all values delimited by commas as separate headers.
对äºååºé¦é¨ï¼ä½¿ç¨ shdr()ï¼
示ä¾ï¼æ£æ¥æ¯å¦è®¾ç½®äº "connection: close" ï¼
hdr_beg <string>
hdr_beg(header) <string>
ä»»ä½ä¸ä¸ª header çå¼æ¯ä»¥ string èµ·å§çï¼è¿å true
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_beg()ï¼
hdr_cnt <integer>
hdr_cnt(header) <integer>
å¦ææå®ç header åºç°ç次æ°å¨æå®èå´å ï¼æå¹é æå®çå¼ï¼è¿å trueï¼
ä¸è¡ header è¯å¥å¦æå å«å¤ä¸ªå¼ï¼å°è¢«å¤æ¬¡è®¡æ°ï¼
ç¨äºæ£æ¥æå® header çæ¯å¦åå¨ï¼æ¯å¦è¢«æ»¥ç¨ï¼
éè¿æç»å«æå¤ä¸ªæå® header ç请æ±ï¼å¯é»æ¡ request smuggling attacksï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_cnt()ï¼
hdr_dir <string>
hdr_dir(header) <string>
ç¨äºæ件åæç®å½åå¹é ï¼å½æ个 header å å«è¢« / åéç stringï¼è¿å trueï¼
å¯ä¸ Referer èå使ç¨ï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_dir()ï¼
hdr_dom <string>
hdr_dom(header) <string>
ç¨äºååå¹é ï¼å¯ä¸ Host header ä¸èµ·ä½¿ç¨ï¼å½æ个 header å å«è¢« . åéç stringï¼è¿å trueï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_dom()ï¼
hdr_end <string>
hdr_end(header) <string>
å½ä»»ä½ä¸ä¸ª header çå¼æ¯ä»¥ string ç»æçï¼è¿å true
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_end()ï¼
hdr_ip <ip_address>
hdr_ip(header) <ip_address>
å½æ个 header çå¼å å«å¹é <ip_address> çå¼ï¼è¿å trueï¼
éå¸¸ä¸ X-Forwarded-For or X-Client-IP ä¸èµ·ä½¿ç¨ï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_ip()ï¼
hdr_len <integer>
hdr_len(<header>) <integer>
è³å°æä¸ä¸ª header ç length ä¸æå®çå¼æè èå´å¹é æ¶ï¼è¿å trueï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_len()ï¼
hdr_reg <regex>
hdr_reg(header) <regex>
æä¸ä¸ª header ä¸æ£å表达å¼å¹é æ¶ï¼è¿å trueï¼å¯å¨ä»»ä½æ¶å使ç¨ï¼
注æï¼æ£åå¹é æ¯å ¶ä»å¹é æ´æ ¢ï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_reg()ï¼
hdr_sub <string>
hdr_sub(header) <string>
æä¸ä¸ª header å å«å ¶ä¸ä¸ä¸ª string æ¶ï¼è¿å trueï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_sub()ï¼
hdr_val <integer>
hdr_val(header) <integer>
æä¸ä¸ª header èµ·å§çæ°åï¼ä¸æå®å¼æèå´å¹é ï¼å¯ç¨äºéå¶ content-lengthï¼åªæ¥ååçé¿åº¦ç请æ±ï¼
对äºååºé¦é¨ï¼ä½¿ç¨ shdr_val()ï¼
http_auth(userlist)
http_auth_group(userlist) <group> [<group>]*
ä»å®¢æ·ç«¯æ¶å°ç认è¯ä¿¡æ¯ä¸ userlist ä¸è®°å½çå¹é æ¶ï¼è¿å trueï¼
ç®ååªæ¯æ http basic authï¼
http_first_req
å¦æå¤çç请æ±æ¯è¿æ¥ç第ä¸ä¸ªè¯·æ±ï¼è¿å trueï¼
method <string>
ç¨äºæ£æ¥ HTTP 请æ±çæ¹æ³ï¼å¹é æ¶ï¼è¿å trueï¼
path <string>
请æ±ä¸ç path é¨åï¼ä»¥ / èµ·å§ï¼å° ? 为æ¢çé¨åï¼ï¼ä¸æ个 string ç¸çæ¶ï¼è¿å trueï¼
å¯ç¨äºå¹é æ个æ件ï¼æ¯å¦ï¼/favicon.ico
path_beg <string>
å½ path 以æ个 string 为起å§ï¼è¿å trueï¼å¯ç¨äºåéæäºç®å½åå° alternative backendï¼
path_dir <string>
å½ path ä¸å å«ä»¥ / åéç string æ¶ï¼è¿å trueï¼å¯ç¨äºå¹é æ件åæç®å½åï¼
path_dom <string>
å½ path ä¸å å«ä»¥ . åéç string æ¶ï¼è¿å trueï¼å¯ç¨äºååå¹é ï¼
path_end <string>
å½ path 以æ个 string 为ç»ææ¶ï¼è¿å trueï¼å¯ç¨äºæ§å¶æ件æ©å±åï¼
path_len <integer>
å½ path çé¿åº¦ä¸æå®å¼æèå´å¹é æ¶ï¼è¿å trueï¼å¯ç¨äºæ£æµ abusive requestsï¼
path_reg <regex>
å½ path ä¸æ£å表达å¼å¹é æ¶ï¼è¿å trueï¼
path_sub <string>
å½ path å å«æ个 string æ¶ï¼è¿å trueï¼å¯ç¨äºæ£æµ path ä¸çæå®æ¨¡å¼ï¼æ¯å¦ â../âï¼
req_ver <string>
ç¨äºæ£æ¥ HTTP 请æ±ççæ¬ï¼æ¯å¦ 1.0ï¼
status <integer>
ç¨äºæ£æ¥ HTTP response çç¶æç ï¼æ¯å¦ ï¼
å¯æ ¹æ®ç¶æç åä¸å®çå¨ä½ï¼æ¯å¦ï¼å¦æ response çç¶æç ä¸æ¯ 3xxï¼åå é¤ Location headerï¼
url <string>
åºç¨äºè¯·æ±ä¸çæ´ä¸ª URLï¼çæ£çç¨å¤æ¯å¹é *ï¼å·²æä¸ä¸ªé¢å®ä¹ç ACLï¼ HTTP_URL_STARï¼
url_beg <string>
å½ URL 以æ个 string èµ·å§æ¶ï¼è¿å trueï¼å¯ç¨äºæ£æ¥æ¯å¦ä»¥ / æè æ个åè®®ç scheme èµ·å§ï¼
url_dir <string>
å¦æ URL ä¸å å«ä»¥ / åéç stringï¼è¿å trueï¼ç¨äºæ件ååç®å½åå¹é ï¼
url_dom <string>
å¦æ URL ä¸å å«ä»¥ . åéç stringï¼è¿å trueï¼ç¨äºååå¹é ï¼
url_end <string>
å½ URL 以æ个 string ç»ææ¶ï¼è¿å trueï¼ç¨å¤å¾å°ï¼
url_ip <ip_address>
ç¨äºæ£æ¥ HTTP 请æ±ä¸ï¼ç»å¯¹ URI ä¸ææå®ç IP å°åï¼å¯ç¨äºæ ¹æ® IP å°ååèµæºç访é®éå¶ï¼
è· http_proxy ä¸èµ·ç¨æ¶å¯åæ¥ä½ç¨ï¼
url_len <integer>
å½ URL çé¿åº¦ä¸æå®å¼æèå´å¹é æ¶ï¼è¿å trueï¼å¯ç¨äºæ£æµ abusive requestsï¼
url_port <integer>
ç¨äºæ£æ¥ HTTP 请æ±ä¸ï¼ç»å¯¹ URI ä¸ææå®ç PORT å°åï¼å¯ç¨äºæ ¹æ® PORT å°ååèµæºç访é®éå¶ï¼
è· http_proxy ä¸èµ·ç¨æ¶å¯åæ¥ä½ç¨ï¼
注æï¼å¦æ请æ±ä¸æ²¡ææå®ç«¯å£ï¼å表示端å£ä¸º ï¼
url_reg <regex>
å½ URL ä¸æ£å表达å¼å¹é æ¶ï¼è¿å trueï¼
url_sub <string>
å½ URL å å«æ个 string æ¶ï¼è¿å trueï¼å¯ç¨äºæ£æ¥ query string ä¸çæäº patternï¼
é¢å®ä¹ç ACLs ä¸éè¦å£°æï¼å¯ä»¥ç´æ¥ä½¿ç¨ãå®ä»¬çå½åé½æ¯å¤§ååæ¯ã
æäº actions åªå¨æ»¡è¶³äºææçæ¡ä»¶æ¶æè½æ§è¡ï¼æ¡ä»¶æ¯ ACLs çé»è¾ç»åï¼
æä¸ä¸ªå¯ç¨çé»è¾è¿ç®ç¬¦ï¼
ä¸ä¸ªæ¡ä»¶çææï¼
actions é åæ¡ä»¶ï¼
ä¾å¦ï¼æé ä¸ä¸ªæ¡ä»¶ï¼å¸æé»æ¡æ»¡è¶³æ¡ä»¶ HTTP 请æ±ï¼æ»¡è¶³å¦ä¸æ¡ä»¶ä¹ä¸æ¶ï¼æç»è¯¥è¯·æ±ï¼
è§åæ¯ï¼
ä¾2.
å»ºç« url_static æµè¯ï¼å½ path 以 /staticã/imagesã/imgã/css èµ·å§ï¼æè 以 .gifã.pngã.jpgã.cssã.js ç»å°¾ï¼è¿å trueï¼
å»ºç« host_www æµè¯ï¼å½è¯·æ±ç Host é¦é¨å段以 www èµ·å§ï¼è¿å trueï¼å¿½ç¥å¤§å°åï¼
å»ºç« host_static æµè¯ï¼å½è¯·æ±ç Host é¦é¨å段以 img. video. download. ftp. ä¹ä¸ä¸ºèµ·å§ï¼è¿å trueï¼å¿½ç¥å¤§å°åï¼
满足 host_static æµè¯ï¼æè host_www AND url_static æµè¯ç请æ±ï¼è½¬åç» static backendï¼
åªæ»¡è¶³ host_www æµè¯ç请æ±ï¼è½¬å www backendï¼
HAProxy æ¯æ使ç¨å¿åç ACLsï¼ä¸éè¦äºå 声æï¼å®ä»¬å¿ 须被 { ACLs } æ¬èµ·æ¥ï¼æ³¨æç©ºæ ¼ï¼ä¾å¦ï¼
ä¸è¬èè¨ï¼ä¸å»ºè®®ä½¿ç¨å¿åç ACLï¼å 为æ´å®¹æåºç°é误ï¼
åªæ对äºç®å ACLsï¼æ¯å¦å¹é ä¸ä¸ª src IPå°åï¼è¿æ¶ä½¿ç¨å¿åæ´å®¹æé 读ï¼
The stickiness features relies on pattern extraction in the request and
response. Sometimes the data needs to be converted first before being stored,
for instance converted from ASCII to IP or upper case to lower case.
All these operations of data extraction and conversion are defined as
"pattern extraction rules". A pattern rule always has the same format. It
begins with a single pattern fetch word, potentially followed by a list of
arguments within parenthesis then an optional list of transformations. As
much as possible, the pattern fetch functions use the same name as their
equivalent used in ACLs.
The list of currently supported pattern fetch functions is the following :
src This is the source IPv4 address of the client of the session.
It is of type IP and only works with such tables.
dst This is the destination IPv4 address of the session on the
client side, which is the address the client connected to.
It can be useful when running in transparent mode. It is of
type IP and only works with such tables.
dst_port This is the destination TCP port of the session on the client
side, which is the port the client connected to. This might be
used when running in transparent mode or when assigning dynamic
ports to some clients for a whole application session. It is of
type integer and only works with such tables.
hdr(name) This extracts the last occurrence of header <name> in an HTTP
request and converts it to an IP address. This IP address is
then used to match the table. A typical use is with the
x-forwarded-for header.
The currently available list of transformations include :
lower Convert a string pattern to lower case. This can only be placed
after a string pattern fetch function or after a conversion
function returning a string type. The result is of type string.
upper Convert a string pattern to upper case. This can only be placed
after a string pattern fetch function or after a conversion
function returning a string type. The result is of type string.
ipmask(mask) Apply a mask to an IPv4 address, and use the result for lookups
and storage. This can be used to make all hosts within a
certain mask to share the same table entries and as such use
the same server. The mask can be passed in dotted form (eg:
...0) or in CIDR form (eg: ).
超级NB的黑科技,实现socket进程间迁移!
今天我们将探讨一项令人瞩目的技术:实现socket句柄在进程间的迁移。在服务器领域,我们经常需要管理大量的溯源码记录server实例。这些实例需要处理数以万计的连接和繁重的网络请求。如果能轻而易举地控制这些连接,像操作乐高积木一样,那么在软件升级时,我们就可以先启动一个新版本的进程,然后将老进程的socket逐个转移到新进程中,实现无缝升级。这项技术,Facebook已成功实践,被称为SocketTakeover。虽然这项技术很有用,但在搜索引擎中却难以找到相关资料。也许大家都在忙于研究茴香豆的合宙源码茴字怎么写,无暇他顾。今天,就由我为大家揭开这项技术的神秘面纱,让你的吹牛资本更上一层楼。这项功能,是基于Linux底层系统调用函数sendmsg()和recvmsg()实现的。
首先,我们需要了解c语言网络编程的基础。通常,我们会通过listen函数注册监听地址,然后使用accept函数接收新连接。例如:
```c
int listen_fd = socket(addr->ss_family, SOCK_STREAM, 0);
...
bind(listen_fd, (struct sockaddr*)addr, addrlen);
...
int accept_fd = accept(fd, (struct sockaddr*)&addr, &addrlen);
```
我们的目标,是海量源码资源将listen_fd从一个进程传递到另一个进程。这需要一个通道,而在Linux上,那就是Unix Domain Sockets(UDS)。
UDS在Linux上表现为一个文件,它允许进程通过这个文件进行数据传输,而无需经过网卡等物理设备,因此速度极快。今天,我们不关注它的速度,而是关注它的实用性。通过bind函数,我们可以在UDS文件上接收连接,就像在端口上接收连接一样。
```c
struct sockaddr_un addr;
char*path = "/tmp/xjjdog.sock";
int fd;
fd = socket(AF_UNIX, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, strlen(path));
addrlen = sizeof(addr.sun_family) + strlen(path);
err = bind(fd, (struct sockaddr*)&addr, addrlen);
...
accept_fd = accept(fd, (struct sockaddr*)&addr, &addrlen);
```
其他进程,现在可以通过端口或UDS文件连接到我们的服务。
接下来,我们来看迁移的过程。关键在于sendmsg函数的第二个参数——msghdr结构体。msghdr结构体包含了一些iov(输入/输出缓冲区)和控制信息。其中,控制信息可以通过CMSG_FIRSTHDR宏获取,它指向cmsghdr结构体。cmsghdr结构体中有一个cmsg_type成员,用于指定控制信息的类型。在这里,我们关注SCM_RIGHTS类型,它允许我们从一个进程发送文件句柄到另一个进程。
```c
struct msghdr msg;
...
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
// 设置cmsg_data为socketfd列表
int* fds = (int*)CMSG_DATA(cmsg);
```
通过sendmsg函数,socket句柄就被发送到另一个进程了。
接收方,则需要使用recvmsg函数,并解析cmsghdr结构体,从cmsg_data中获取句柄列表。实际上,socket句柄在进程中只是一个引用,真正的句柄在内核中。迁移,不过是将一个引用从内核中移除,然后添加到另一个进程中。
对于普通fd,我们需要调用与原始连接到来时相同的代码逻辑。因此,迁移过程包括:迁移listener fd到新进程并开始监听,迁移大量的socket连接,并逐步在新进程中还原它们。完成后,老进程就可以安全地关闭了。
这是一项具有革命性的技术,已经在一些主流应用中得到应用。例如,HAProxy用于4层网络的负载均衡;Envoy和Istio默认的数据平面软件,也使用类似技术完成热重启。在service mesh的推进过程中,proxy的替换也会使用这种技术,如SOFA。虽然golang和C语言因为API暴露较好,实现起来较为容易,但在Java中,由于缺少这种为Linux定制的API,实现起来就有不少困难。这种技术非常适合无状态的proxy服务,如果有状态的服务尝试使用,可能会有安全风险,但也可以尝试应用在一些中间件上。无论如何,这种技术的出现,肯定会令windowsserver用户羡慕不已。