Merge Mainline
This commit is contained in:
@@ -8,12 +8,12 @@ endif
|
||||
|
||||
LINUX_VERSION-4.9 = .229
|
||||
LINUX_VERSION-4.14 = .187
|
||||
LINUX_VERSION-4.19 = .130
|
||||
LINUX_VERSION-4.19 = .131
|
||||
LINUX_VERSION-5.4 = .50
|
||||
|
||||
LINUX_KERNEL_HASH-4.9.229 = 3256c2835fd95a1a739603e78b02d363eac2ce73a39fa19b13b32da4fc370fdc
|
||||
LINUX_KERNEL_HASH-4.14.187 = 5b223475eaeea196aa7e127d3f253bca5c35d8afdc72ca75230ce1ecdd1454bd
|
||||
LINUX_KERNEL_HASH-4.19.130 = a692c0e61dc885b4d6e66ae7bf202dadf7d5538fbf92766ce7cf8e227fd4f00f
|
||||
LINUX_KERNEL_HASH-4.19.131 = 19dfb9f6cc4ba30104b65dcce7d78240a4ae188cb366747d5f8eae35e98964ba
|
||||
LINUX_KERNEL_HASH-5.4.50 = ad10f4c1e900f4e3eb4903b65dbcb4ca74250de63aa9fa7105b9b3c3f9a8a6e2
|
||||
|
||||
remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1))))
|
||||
|
||||
@@ -998,13 +998,18 @@ do_run_core()
|
||||
core_type="Game"
|
||||
fi
|
||||
|
||||
if [ "$proxy_mode" = "Script" ] || [ -n "$(grep "^ \{0,\}rule-providers:" "$CONFIG_FILE" 2>/dev/null)" ] || [ "$rule_source" = "ConnersHua_provider" ]; then
|
||||
if [ "$proxy_mode" = "Script" ] || [ "$rule_source" = "ConnersHua_provider" ]; then
|
||||
ln -s /etc/openclash/core/clash_tun /etc/openclash/clash 2>/dev/null
|
||||
core_type="Tun"
|
||||
fi
|
||||
|
||||
if [ -n "$(grep "^ \{0,\}rule-providers:" "$RULE_PROVIDER_FILE" 2>/dev/null)" ] && [ -n "$(grep "^ \{0,\}behavior" "$RULE_PROVIDER_FILE" 2>/dev/null |grep -v "^ \{0,\}#")" ]; then
|
||||
ln -s /etc/openclash/core/clash_tun /etc/openclash/clash 2>/dev/null
|
||||
core_type="Tun"
|
||||
fi
|
||||
|
||||
if [ ! -f "/etc/openclash/clash" ] && [ -f "/etc/openclash/core/clash" ] && [ -z "$core_type" ]; then
|
||||
ln -s /etc/openclash/core/clash /etc/openclash/clash 2>/dev/null
|
||||
ln -s /etc/openclash/core/clash /etc/openclash/clash 2>/dev/null
|
||||
fi
|
||||
|
||||
#权限检查
|
||||
|
||||
@@ -346,7 +346,7 @@ o:depends("rule_source", "lhie1")
|
||||
file:seek("set")
|
||||
o = s:taboption("rules", ListValue, "AdBlock", translate("AdBlock"))
|
||||
o:depends("rule_source", "lhie1")
|
||||
o:depends("rule_source", "ConnersHua_provider")
|
||||
--o:depends("rule_source", "ConnersHua_provider")
|
||||
for l in file:lines() do
|
||||
o:value(l)
|
||||
end
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en" dir="ltr"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><link rel="icon" type="image/x-icon" href="https://cdn.jsdelivr.net/gh/Dreamacro/clash/docs/logo.png"/><title>Clash</title><link href="main.592d9cc6ea35f4c8ca4d.css" rel="stylesheet"></head><body><div id="root"></div><script src="js/1.bundle.592d9cc6ea35f4c8ca4d.min.js"></script><script src="js/bundle.592d9cc6ea35f4c8ca4d.min.js"></script></body></html>
|
||||
<!doctype html><html lang="en" dir="ltr"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><link rel="icon" type="image/x-icon" href="https://cdn.jsdelivr.net/gh/Dreamacro/clash/docs/logo.png"/><title>Clash</title><link href="main.0f871e89a0b8ff683256.css" rel="stylesheet"></head><body><div id="root"></div><script src="js/1.bundle.0f871e89a0b8ff683256.min.js"></script><script src="js/bundle.0f871e89a0b8ff683256.min.js"></script></body></html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,28 +1,28 @@
|
||||
/*! modern-normalize v0.6.0 | MIT License | https://github.com/sindresorhus/modern-normalize */*,:after,:before{box-sizing:border-box}:root{-moz-tab-size:4;tab-size:4}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji}hr{height:0}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{padding:0}progress{vertical-align:initial}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}
|
||||
._2MMSFnbhST{stroke-dasharray:890;stroke-dashoffset:890;animation:apL4DUAKgd 3s ease-in-out infinite normal forwards}@keyframes apL4DUAKgd{0%{stroke-dashoffset:890}to{stroke-dashoffset:0}}
|
||||
._3oi0NFbeOm{opacity:.5;width:100%;height:100%;display:flex;justify-content:center;align-items:center}
|
||||
._1rJPiLWN4s{position:fixed;top:0;bottom:0;left:0;right:0;overflow:hidden;padding:20px;background:var(--color-background);color:var(--color-text);text-align:center}._3h_IywJG1l{color:#2a477a;opacity:.6;display:flex;justify-content:center;padding:40px}.aXXDDfyTjE,._3h_IywJG1l{align-items:center}.aXXDDfyTjE{display:inline-flex;color:var(--color-text-secondary)}.aXXDDfyTjE:active,.aXXDDfyTjE:hover{color:#387cec}.aXXDDfyTjE svg{margin-right:5px}
|
||||
._30oJwXNik9{background:var(--color-bg-sidebar);position:relative}._1SsCcpJvxN{display:block}._2r8EkOI78X{display:flex;align-items:center;justify-content:center;padding:25px 0 15px;color:#2a477a;transition:color .3s ease-in-out}@media (max-width:768px){._2r8EkOI78X{display:none}}._2r8EkOI78X:hover{animation:_2KRqAfqV8c .3s ease-in-out 0s infinite alternate}._2r8EkOI78X img{width:80px;height:80px}@keyframes _2KRqAfqV8c{0%{color:#2a477a}to{color:#1f52ac}}@media (max-width:768px){._2vUQ0Hs_C5{display:flex;justify-content:space-between;overflow:scroll}}._8mEn9Wlw1n{color:var(--color-text);text-decoration:none;display:flex;align-items:center;padding:6px 16px}@media screen and (min-width:30em){._8mEn9Wlw1n{padding:8px 20px}}@media (max-width:768px){._8mEn9Wlw1n{flex-direction:column}}._8mEn9Wlw1n svg{color:var(--color-icon);width:22px;height:22px}@media screen and (min-width:30em){._8mEn9Wlw1n svg{width:24px;height:24px}}._1WyHmd6t6y{background:var(--color-sb-active-row-bg)}@media (max-width:768px){._1WyHmd6t6y{background:none;border-bottom:2px solid #387cec}}._2eMIYGbP9O{padding-left:14px;font-size:.75em}@media (max-width:768px){._2eMIYGbP9O{padding-left:0;padding-top:5px}}@media screen and (min-width:30em){._2eMIYGbP9O{font-size:1em}}.nURY8qkFLS{--sz:40px;position:absolute;bottom:10px;left:50%;transform:translateX(-50%);width:var(--sz);height:var(--sz);display:flex;justify-content:center;align-items:center;color:var(--color-text);padding:5px;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;background:none;cursor:pointer;border:1px solid transparent;border-radius:100%}@media (max-width:768px){.nURY8qkFLS{display:none}}.nURY8qkFLS:focus{border-color:var(--color-focus-blue)}
|
||||
.SNYKRrv_2I{height:76px;display:flex;align-items:center}.VG1cD2OYvg{padding:0 15px;font-size:1.7em;text-align:left;margin:0}@media screen and (min-width:30em){.VG1cD2OYvg{padding:0 40px;font-size:2em}}
|
||||
._37kQcxVR4T{color:var(--color-text);display:flex;align-items:center;flex-wrap:wrap}._37kQcxVR4T .sec{padding:10px;width:180px}._37kQcxVR4T .sec div:first-child{color:var(--color-text-secondary);font-size:.7em}._37kQcxVR4T .sec div:nth-child(2){padding:10px 0 0;font-size:1.8em}
|
||||
._1EnK5MMInH{width:100%;height:100%;display:flex;justify-content:center;align-items:center}._39z9L5I2ao{--color1:#ddd;--size:40px;width:var(--size);height:var(--size);margin:10px;background-color:var(--color1);border-radius:100%;animation:_1DSWK2a-pe 1s ease-in-out infinite}@keyframes _1DSWK2a-pe{0%{transform:scale(0)}to{transform:scale(1);opacity:0}}
|
||||
._2rN7aLQPCl{padding:6px 15px}@media screen and (min-width:30em){._2rN7aLQPCl{padding:10px 40px}}
|
||||
._1u5AP7XMF9{padding:0 40px 5px}._2zeyKJDdFH{position:relative;height:40px}._3DQ7SXxKRA{position:absolute;top:50%;transform:translateY(-50%);left:0;width:100%}._1f-XUgRxH1{-webkit-appearance:none;background-color:var(--color-input-bg);background-image:none;border-radius:20px;border:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;height:40px;outline:none;padding:0 15px 0 35px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}._3PLtWxZwrd{position:absolute;top:50%;transform:translateY(-50%);left:10px}
|
||||
._2tpN_G7FeO{display:flex;align-items:center;flex-wrap:wrap;font-size:.9em;padding:10px}._3wuPHKqO5W{color:#eee;flex-shrink:0;text-align:center;width:66px;background:green;border-radius:5px;padding:3px 5px;margin:0 8px}.IwiVCclCSC{flex-shrink:0;color:#999;font-size:14px}._3I1beKAMFt{flex-shrink:0;display:flex;font-family:Roboto Mono,Menlo,monospace;align-items:center;padding:8px 0;width:100%;white-space:pre;overflow:auto}._2MDNI6JESq{margin:0;padding:0;color:var(--color-text)}._2MDNI6JESq li,._2MDNI6JESq li.even{background:var(--color-background)}._3KX1sKJ1QD{padding:10px 40px}._19_8g6kTIV{display:flex;flex-direction:column;align-items:center;justify-content:center;color:#2d2d30}._19_8g6kTIV div:nth-child(2){color:var(--color-text-secondary);font-size:1.4em;opacity:.6}._3ljFcrWmBC{opacity:.3}
|
||||
._3evbv-Ui87{-webkit-user-select:none;-ms-user-select:none;user-select:none;border:1px solid #525252;color:var(--color-text);background:var(--color-toggle-bg);display:flex;position:relative;outline:none}._3evbv-Ui87:focus{border-color:var(--color-focus-blue)}._3evbv-Ui87 input{position:absolute;left:0;opacity:0}._3evbv-Ui87 label{z-index:2;display:flex;align-items:center;justify-content:center;padding:10px 0;cursor:pointer}._1ok8KIb1RH{z-index:1;position:absolute;display:block;left:0;height:100%;transition:left .2s ease-out;background:var(--color-toggle-selected)}
|
||||
._2S85tjFa1n{-webkit-appearance:none;background-color:var(--color-input-bg);background-image:none;border-radius:4px;border:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;height:40px;outline:none;padding:0 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}._2S85tjFa1n:focus{border-color:var(--color-focus-blue)}input::-webkit-inner-spin-button,input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
|
||||
h2._1p7G03ShKD{margin:0;font-size:1.3em}@media screen and (min-width:30em){h2._1p7G03ShKD{font-size:1.5em}}h2._1p7G03ShKD span:nth-child(2){font-size:12px;color:#777;font-weight:400;margin:0 .3em}body.light{--loading-dot-1-1:rgba(0,0,0,0.1);--loading-dot-1-2:rgba(0,0,0,0.5);--loading-dot-1-3:rgba(0,0,0,0.3);--loading-dot-2-1:rgba(0,0,0,0.3);--loading-dot-2-2:rgba(0,0,0,0.1);--loading-dot-2-3:rgba(0,0,0,0.5);--loading-dot-3-1:rgba(0,0,0,0.5);--loading-dot-3-2:rgba(0,0,0,0.3);--loading-dot-3-3:rgba(0,0,0,0.1)}body.dark{--loading-dot-1-1:hsla(0,0%,100%,0.5);--loading-dot-1-2:hsla(0,0%,100%,0.1);--loading-dot-1-3:hsla(0,0%,100%,0.3);--loading-dot-2-1:hsla(0,0%,100%,0.3);--loading-dot-2-2:hsla(0,0%,100%,0.5);--loading-dot-2-3:hsla(0,0%,100%,0.1);--loading-dot-3-1:hsla(0,0%,100%,0.1);--loading-dot-3-2:hsla(0,0%,100%,0.3);--loading-dot-3-3:hsla(0,0%,100%,0.5)}._1l_b31nvKC,._1l_b31nvKC:after,._1l_b31nvKC:before{display:inline-block;vertical-align:middle;width:6px;height:6px;border-radius:50%;font-size:0}._1l_b31nvKC{position:relative;background-color:var(--loading-dot-2-1);animation:AmeWPxQSDb 1s step-start infinite}._1l_b31nvKC:before{content:"";position:absolute;left:-12px;background-color:var(--loading-dot-1-1);animation:_1C49ms67Ai 1s step-start infinite}._1l_b31nvKC:after{content:"";position:absolute;right:-12px;background-color:var(--loading-dot-3-1);animation:p_etI2Ova8 1s step-start infinite}@keyframes _1C49ms67Ai{0%,to{background-color:var(--loading-dot-1-1)}33%{background-color:var(--loading-dot-1-2)}66%{background-color:var(--loading-dot-1-3)}}@keyframes AmeWPxQSDb{0%,to{background-color:var(--loading-dot-2-1)}33%{background-color:var(--loading-dot-2-2)}66%{background-color:var(--loading-dot-2-3)}}@keyframes p_etI2Ova8{0%,to{background-color:var(--loading-dot-3-1)}33%{background-color:var(--loading-dot-3-2)}66%{background-color:var(--loading-dot-3-3)}}
|
||||
@font-face{font-family:Roboto Mono;font-style:normal;font-display:swap;font-weight:400;src:local("Roboto Mono Regular "),local("Roboto Mono-Regular"),url(roboto-mono-latin-400.woff2) format("woff2")}@font-face{font-family:Open Sans;font-style:normal;font-display:swap;font-weight:400;src:local("Open Sans Regular "),local("Open Sans-Regular"),url(open-sans-latin-400.woff2) format("woff2")}@font-face{font-family:Open Sans;font-style:normal;font-display:swap;font-weight:700;src:local("Open Sans Bold "),local("Open Sans-Bold"),url(open-sans-latin-700.woff2) format("woff2")}.border-bottom,.border-left,.border-top,.relative{position:relative}.border-top:before{top:0}.border-bottom:after,.border-top:before{position:absolute;content:"";height:1px;width:100%;transform:scaleY(.5) translateZ(0);left:0;right:0;background:#555}.border-bottom:after{bottom:0}.border-left:before{position:absolute;content:"";height:100%;width:1px;transform:scaleX(.5) translateZ(0);top:0;bottom:0;background:#555;left:0}*,:after,:before{box-sizing:border-box}:root{--font-mono:"Roboto Mono",Menlo,monospace;--font-normal:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,"PingFang SC","Microsoft YaHei","微软雅黑",Arial,sans-serif;--color-focus-blue:#1a73e8}body{font-family:Open Sans,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,PingFang SC,Microsoft YaHei,微软雅黑;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;margin:0;padding:0}body,body.dark{--color-background:#202020;--color-text:#ddd;--color-text-secondary:#ccc;--color-text-highlight:#fff;--color-bg-sidebar:#2d2d30;--color-sb-active-row-bg:#494b4e;--color-input-bg:#2d2d30;--color-input-border:#3f3f3f;--color-toggle-bg:#353535;--color-toggle-selected:#181818;--color-icon:#c7c7c7;--color-separator:#333;--color-btn-bg:#232323;--color-btn-fg:#bebebe;--color-bg-proxy:#303030;--color-row-odd:#282828;--bg-modal:#1f1f20;--bg-near-transparent:hsla(0,0%,100%,0.1);--select-border-color:#040404;--select-bg-hover:url("data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 7l3 4H1l3-4zM4 17l-3-4h6l-3 4z' fill='%23fff'/%3E%3C/svg%3E")}body.light{--color-background:#fbfbfb;--color-text:#222;--color-text-secondary:#646464;--color-text-highlight:#040404;--color-bg-sidebar:#e7e7e7;--color-sb-active-row-bg:#d0d0d0;--color-input-bg:#fff;--color-input-border:silver;--color-toggle-bg:#fff;--color-toggle-selected:#d7d7d7;--color-icon:#5b5b5b;--color-separator:#ccc;--color-btn-bg:#f4f4f4;--color-btn-fg:#101010;--color-bg-proxy:#e7e7e7;--color-row-odd:#f5f5f5;--bg-modal:#fbfbfb;--bg-near-transparent:rgba(0,0,0,0.1);--select-border-color:#999;--select-bg-hover:url("data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 7l3 4H1l3-4zM4 17l-3-4h6l-3 4z' fill='%23222'/%3E%3C/svg%3E")}.flexCenter{display:flex;align-items:center;justify-content:center}.fabgrp{position:fixed;z-index:3;right:20px;bottom:20px}
|
||||
._3hz7LVhvUv:focus{outline:none}._3HF-KB9mgO{display:flex;justify-content:center;align-items:center}._3HF-KB9mgO ._3HzgPICn91{color:#2d2d30;opacity:.4;transition:opacity .4s}._3HF-KB9mgO ._3HzgPICn91:hover{opacity:.7}._1wpZuvoD5I{padding:30px 0 10px}.L7jTy-EFJ2{display:flex}.L7jTy-EFJ2 div{flex:1 1 auto}.L7jTy-EFJ2 div:nth-child(2){flex-grow:0;flex-basis:120px;margin-left:10px}._2fehqRU9GV{padding:30px 0 10px;display:flex;justify-content:flex-end;align-items:center}
|
||||
._2A0HoxnDqc{-webkit-appearance:none;outline:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;position:relative;display:inline-flex;align-items:center;justify-content:center;color:var(--color-btn-fg);background:var(--color-btn-bg);border:1px solid #555;border-radius:100px;font-size:.85em;padding:4px 7px}._2A0HoxnDqc:focus{border-color:var(--color-focus-blue)}._2A0HoxnDqc:hover{background:#387cec;border:1px solid #387cec;color:#fff}._2A0HoxnDqc:active{transform:scale(.97)}@media screen and (min-width:30em){._2A0HoxnDqc{font-size:1em;padding:6px 12px}}._2A0HoxnDqc.rBrOhcv1IU{border-color:transparent;background:none}._2A0HoxnDqc.rBrOhcv1IU:focus{border-color:var(--color-focus-blue)}._2A0HoxnDqc.rBrOhcv1IU:hover{color:#fff;background:#387cec;border:1px solid #387cec}.CtvjIaf7QB{margin-right:5px;display:inline-flex;align-items:center;justify-content:center}._2KAqQdptfT{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);display:inline-flex}
|
||||
._2id19fefQX{display:flex;flex-wrap:wrap}._2QQQyNTKoG{flex-grow:0;margin-right:10px;margin-bottom:10px;cursor:pointer;border:2px solid transparent}.XJkW0wZSAx{border-color:#387cec}
|
||||
._2OZZRrEL0J>div{min-width:345px}@media screen and (min-width:30em){._2OZZRrEL0J>div{width:360px}}._2OZZRrEL0J,.lF_ZoyIdZN{padding:6px 15px 15px}@media screen and (min-width:30em){._2OZZRrEL0J,.lF_ZoyIdZN{padding:10px 40px 40px}}.VduFBb2hWX{padding:0 15px}@media screen and (min-width:30em){.VduFBb2hWX{padding:0 40px}}.VduFBb2hWX>div{border-top:1px dashed #373737}._2NQoBOQcGA{padding:16px 0}
|
||||
._73r9mFp69q{display:grid;grid-template-columns:repeat(11,minmax(-webkit-max-content,auto));grid-template-columns:repeat(11,minmax(max-content,auto))}.hEAcjybq1r{padding:8px 10px;height:50px;background:var(--color-background);position:-webkit-sticky;position:sticky;top:0;font-size:.8em;text-align:center;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;align-items:center;justify-content:space-between}.hEAcjybq1r:hover{color:var(--color-text-highlight)}._1x7JSEXzR8{padding:8px 13px;font-size:.9em;font-family:var(--font-normal)}._1x7JSEXzR8._3n5sGVMC-F{background:var(--color-row-odd)}._26SQDJZWya{text-align:right}._3LKH-WXUjR{display:inline-flex;margin-left:10px;width:16px;height:16px}._1CoVX1S_So{transform:rotate(180deg)}
|
||||
h2._1p7G03ShKD{margin:0;font-size:1.3em}@media screen and (min-width:30em){h2._1p7G03ShKD{font-size:1.5em}}h2._1p7G03ShKD span:nth-child(2){font-size:12px;color:#777;font-weight:400;margin:0 .3em}body.light{--loading-dot-1-1:rgba(0,0,0,0.1);--loading-dot-1-2:rgba(0,0,0,0.5);--loading-dot-1-3:rgba(0,0,0,0.3);--loading-dot-2-1:rgba(0,0,0,0.3);--loading-dot-2-2:rgba(0,0,0,0.1);--loading-dot-2-3:rgba(0,0,0,0.5);--loading-dot-3-1:rgba(0,0,0,0.5);--loading-dot-3-2:rgba(0,0,0,0.3);--loading-dot-3-3:rgba(0,0,0,0.1)}body.dark{--loading-dot-1-1:hsla(0,0%,100%,0.5);--loading-dot-1-2:hsla(0,0%,100%,0.1);--loading-dot-1-3:hsla(0,0%,100%,0.3);--loading-dot-2-1:hsla(0,0%,100%,0.3);--loading-dot-2-2:hsla(0,0%,100%,0.5);--loading-dot-2-3:hsla(0,0%,100%,0.1);--loading-dot-3-1:hsla(0,0%,100%,0.1);--loading-dot-3-2:hsla(0,0%,100%,0.3);--loading-dot-3-3:hsla(0,0%,100%,0.5)}._1l_b31nvKC,._1l_b31nvKC:after,._1l_b31nvKC:before{display:inline-block;vertical-align:middle;width:6px;height:6px;border-radius:50%;font-size:0}._1l_b31nvKC{position:relative;background-color:var(--loading-dot-2-1);animation:AmeWPxQSDb 1s step-start infinite}._1l_b31nvKC:before{content:"";position:absolute;left:-12px;background-color:var(--loading-dot-1-1);animation:_1C49ms67Ai 1s step-start infinite}._1l_b31nvKC:after{content:"";position:absolute;right:-12px;background-color:var(--loading-dot-3-1);animation:p_etI2Ova8 1s step-start infinite}@keyframes _1C49ms67Ai{0%,to{background-color:var(--loading-dot-1-1)}33%{background-color:var(--loading-dot-1-2)}66%{background-color:var(--loading-dot-1-3)}}@keyframes AmeWPxQSDb{0%,to{background-color:var(--loading-dot-2-1)}33%{background-color:var(--loading-dot-2-2)}66%{background-color:var(--loading-dot-2-3)}}@keyframes p_etI2Ova8{0%,to{background-color:var(--loading-dot-3-1)}33%{background-color:var(--loading-dot-3-2)}66%{background-color:var(--loading-dot-3-3)}}
|
||||
._1r-KsYFNaj{position:relative;padding:10px 0}._1r-KsYFNaj input{-webkit-appearance:none;background-color:initial;background-image:none;border:none;border-radius:0;border-bottom:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;height:40px;outline:none;padding:0 8px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}._1r-KsYFNaj input:focus{border-color:var(--color-focus-blue)}._1r-KsYFNaj label{position:absolute;left:8px;bottom:22px;transition:transform .15s ease-in-out;transform-origin:0 0}._1r-KsYFNaj input:focus+label,._1r-KsYFNaj label.Hn6h5kxOg7{transform:scale(.75) translateY(-25px)}._1r-KsYFNaj input:focus+label{color:var(--color-focus-blue)}
|
||||
._2MMSFnbhST{stroke-dasharray:890;stroke-dashoffset:890;animation:apL4DUAKgd 3s ease-in-out infinite normal forwards}@keyframes apL4DUAKgd{0%{stroke-dashoffset:890}to{stroke-dashoffset:0}}
|
||||
._3D3ZNp4oBz{background:none;position:fixed;top:0;bottom:0;left:0;right:0;transform:none;padding:0;border-radius:0;display:flex;justify-content:center}.tgH3yv-xGR{position:relative;top:10%;margin-left:20px;margin-right:20px}._3MMuzHtwZL{background:#222}
|
||||
.ctrHyq7uir{position:fixed;top:0;right:0;left:0;bottom:0;background:#444;z-index:1024}._17mHpKiOUD{outline:none;position:relative;color:#ddd;top:50%;left:50%;transform:translate(-50%,-50%);background:#444;padding:20px;border-radius:10px}
|
||||
._3R-iKwDVj-{background-color:rgba(0,0,0,.6)}._1vh9rFTHqn{background-color:var(--bg-modal);color:var(--color-text);max-width:300px;line-height:1.4;transform:translate(-50%,-50%) scale(1.2);opacity:.6;transition:all .3s ease}._3bTCBReMiZ{opacity:1;transform:translate(-50%,-50%) scale(1)}._1lwetyauPD{display:flex;align-items:center;justify-content:center;margin-top:30px}
|
||||
.rtf{box-sizing:border-box;margin:25px;position:fixed;white-space:nowrap;z-index:9998;padding-left:0;list-style:none}.rtf.open .rtf--mb>*{transition:transform .2s ease-in-out}.rtf.open .rtf--mb{background:rgba(56,124,236,.92);box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.rtf.open .rtf--mb>ul{list-style:none;margin:0;padding:0}.rtf.open .rtf--ab__c:hover>span,.rtf.open .rtf--ab__c>span.always-show{transition:opacity .2s ease-in-out;opacity:.9}.rtf.open .rtf--ab__c:first-child{transform:translateY(-60px) scale(1);transition-delay:.03s}.rtf.open .rtf--ab__c:first-child.top{transform:translateY(60px) scale(1)}.rtf.open .rtf--ab__c:nth-child(2){transform:translateY(-120px) scale(1);transition-delay:.09s}.rtf.open .rtf--ab__c:nth-child(2).top{transform:translateY(120px) scale(1)}.rtf.open .rtf--ab__c:nth-child(3){transform:translateY(-180px) scale(1);transition-delay:.12s}.rtf.open .rtf--ab__c:nth-child(3).top{transform:translateY(180px) scale(1)}.rtf.open .rtf--ab__c:nth-child(4){transform:translateY(-240px) scale(1);transition-delay:.15s}.rtf.open .rtf--ab__c:nth-child(4).top{transform:translateY(240px) scale(1)}.rtf.open .rtf--ab__c:nth-child(5){transform:translateY(-300px) scale(1);transition-delay:.18s}.rtf.open .rtf--ab__c:nth-child(5).top{transform:translateY(300px) scale(1)}.rtf.open .rtf--ab__c:nth-child(6){transform:translateY(-360px) scale(1);transition-delay:.21s}.rtf.open .rtf--ab__c:nth-child(6).top{transform:translateY(360px) scale(1)}.rtf--mb__c{padding:25px;margin:-25px}.rtf--mb__c :last-child{margin-bottom:0}.rtf--mb__c:hover>span,.rtf--mb__c>span.always-show{transition:opacity .2s ease-in-out;opacity:.9}.rtf--mb__c>span{opacity:0;transition:opacity .2s ease-in-out;position:absolute;top:50%;transform:translateY(-50%);margin-right:6px;margin-left:4px;background:rgba(0,0,0,.75);padding:2px 4px;border-radius:2px;color:#fff;font-size:13px;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28)}.rtf--mb__c>span.right{right:100%}.rtf--mb{height:48px;width:48px;z-index:9999;background:#387cec;display:inline-flex;justify-content:center;align-items:center;position:relative;border:none;border-radius:50%;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28);cursor:pointer;outline:none;padding:0;-webkit-user-drag:none;font-weight:700;color:#f1f1f1;font-size:18px}.rtf--ab__c,.rtf--mb>*{transition:transform .2s ease-in-out}.rtf--ab__c{display:block;position:absolute;top:0;right:1px;padding:10px 0;margin:-10px 0}.rtf--ab__c>span{opacity:0;transition:opacity .2s ease-in-out;position:absolute;top:50%;transform:translateY(-50%);margin-right:6px;background:rgba(0,0,0,.75);padding:2px 4px;border-radius:2px;color:#fff;font-size:13px;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28)}.rtf--ab__c>span.right{right:100%}.rtf--ab__c:first-child{transform:translateY(-60px) scale(0);transition-delay:.21s}.rtf--ab__c:first-child.top{transform:translateY(60px) scale(0)}.rtf--ab__c:nth-child(2){transform:translateY(-120px) scale(0);transition-delay:.18s}.rtf--ab__c:nth-child(2).top{transform:translateY(120px) scale(0)}.rtf--ab__c:nth-child(3){transform:translateY(-180px) scale(0);transition-delay:.15s}.rtf--ab__c:nth-child(3).top{transform:translateY(180px) scale(0)}.rtf--ab__c:nth-child(4){transform:translateY(-240px) scale(0);transition-delay:.12s}.rtf--ab__c:nth-child(4).top{transform:translateY(240px) scale(0)}.rtf--ab__c:nth-child(5){transform:translateY(-300px) scale(0);transition-delay:.09s}.rtf--ab__c:nth-child(5).top{transform:translateY(300px) scale(0)}.rtf--ab__c:nth-child(6){transform:translateY(-360px) scale(0);transition-delay:.03s}.rtf--ab__c:nth-child(6).top{transform:translateY(360px) scale(0)}.rtf--ab{height:40px;width:40px;margin-right:4px;background-color:#aaa;display:inline-flex;justify-content:center;align-items:center;position:relative;border:none;border-radius:50%;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28);cursor:pointer;outline:none;padding:0;-webkit-user-drag:none;font-weight:700;color:#f1f1f1;font-size:16px;z-index:10000}.rtf--ab:hover{background:#387cec;border:1px solid #387cec;color:#fff}.rtf--ab:focus{border-color:var(--color-focus-blue)}
|
||||
._2OZZRrEL0J>div{min-width:345px}@media screen and (min-width:30em){._2OZZRrEL0J>div{width:360px}}._2OZZRrEL0J,.lF_ZoyIdZN{padding:6px 15px 15px}@media screen and (min-width:30em){._2OZZRrEL0J,.lF_ZoyIdZN{padding:10px 40px 40px}}.VduFBb2hWX{padding:0 15px}@media screen and (min-width:30em){.VduFBb2hWX{padding:0 40px}}.VduFBb2hWX>div{border-top:1px dashed #373737}._2NQoBOQcGA{padding:16px 0}
|
||||
.SNYKRrv_2I{height:76px;display:flex;align-items:center}.VG1cD2OYvg{padding:0 15px;font-size:1.7em;text-align:left;margin:0}@media screen and (min-width:30em){.VG1cD2OYvg{padding:0 40px;font-size:2em}}
|
||||
._2S85tjFa1n{-webkit-appearance:none;background-color:var(--color-input-bg);background-image:none;border-radius:4px;border:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;height:40px;outline:none;padding:0 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}._2S85tjFa1n:focus{border-color:var(--color-focus-blue)}input::-webkit-inner-spin-button,input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
|
||||
._2id19fefQX{display:flex;flex-wrap:wrap}._2QQQyNTKoG{flex-grow:0;margin-right:10px;margin-bottom:10px;cursor:pointer;border:2px solid transparent}.XJkW0wZSAx{border-color:#387cec}
|
||||
._3evbv-Ui87{-webkit-user-select:none;-ms-user-select:none;user-select:none;border:1px solid #525252;color:var(--color-text);background:var(--color-toggle-bg);display:flex;position:relative;outline:none}._3evbv-Ui87:focus{border-color:var(--color-focus-blue)}._3evbv-Ui87 input{position:absolute;left:0;opacity:0}._3evbv-Ui87 label{z-index:2;display:flex;align-items:center;justify-content:center;padding:10px 0;cursor:pointer}._1ok8KIb1RH{z-index:1;position:absolute;display:block;left:0;height:100%;transition:left .2s ease-out;background:var(--color-toggle-selected)}
|
||||
.react-tabs{-webkit-tap-highlight-color:transparent}.react-tabs__tab-list{margin:0 0 10px;padding:0 30px}.react-tabs__tab{display:inline-flex;align-items:center;border:1px solid transparent;border-radius:5px;bottom:-1px;position:relative;list-style:none;padding:6px 10px;cursor:pointer;font-size:1.2em;opacity:.5}.react-tabs__tab--selected{opacity:1}.react-tabs__tab--disabled{color:GrayText;cursor:default}.react-tabs__tab:focus{border-color:#0188fe;outline:none}.react-tabs__tab:focus:after{content:"";position:absolute}.react-tabs__tab-panel{display:none}.react-tabs__tab-panel--selected{display:block}
|
||||
.duOnUwq-nI{height:100%;display:flex;color:var(--color-background);opacity:.1}.CCpULSE9Uh,.duOnUwq-nI{align-items:center;justify-content:center}.CCpULSE9Uh{font-family:var(--font-normal);font-size:.75em;margin-left:3px;padding:2px 7px;display:inline-flex;background-color:var(--bg-near-transparent);border-radius:30px}.peSK87gUob{margin:0 30px;width:100%;max-width:350px;justify-self:flex-end}._1nDSx5DASl{-webkit-appearance:none;background-color:var(--color-input-bg);background-image:none;border-radius:18px;border:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;height:36px;outline:none;padding:0 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}
|
||||
._1r-KsYFNaj{position:relative;padding:10px 0}._1r-KsYFNaj input{-webkit-appearance:none;background-color:initial;background-image:none;border:none;border-radius:0;border-bottom:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;height:40px;outline:none;padding:0 8px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}._1r-KsYFNaj input:focus{border-color:var(--color-focus-blue)}._1r-KsYFNaj label{position:absolute;left:8px;bottom:22px;transition:transform .15s ease-in-out;transform-origin:0 0}._1r-KsYFNaj input:focus+label,._1r-KsYFNaj label.Hn6h5kxOg7{transform:scale(.75) translateY(-25px)}._1r-KsYFNaj input:focus+label{color:var(--color-focus-blue)}
|
||||
._3hz7LVhvUv:focus{outline:none}._3HF-KB9mgO{display:flex;justify-content:center;align-items:center}._3HF-KB9mgO ._3HzgPICn91{color:#2d2d30;opacity:.4;transition:opacity .4s}._3HF-KB9mgO ._3HzgPICn91:hover{opacity:.7}._1wpZuvoD5I{padding:30px 0 10px}.L7jTy-EFJ2{display:flex}.L7jTy-EFJ2 div{flex:1 1 auto}.L7jTy-EFJ2 div:nth-child(2){flex-grow:0;flex-basis:120px;margin-left:10px}._2fehqRU9GV{padding:30px 0 10px;display:flex;justify-content:flex-end;align-items:center}
|
||||
._3D3ZNp4oBz{background:none;position:fixed;top:0;bottom:0;left:0;right:0;transform:none;padding:0;border-radius:0;display:flex;justify-content:center}.tgH3yv-xGR{position:relative;top:10%;margin-left:20px;margin-right:20px}._3MMuzHtwZL{background:#222}
|
||||
@font-face{font-family:Roboto Mono;font-style:normal;font-display:swap;font-weight:400;src:local("Roboto Mono Regular "),local("Roboto Mono-Regular"),url(roboto-mono-latin-400.woff2) format("woff2")}@font-face{font-family:Open Sans;font-style:normal;font-display:swap;font-weight:400;src:local("Open Sans Regular "),local("Open Sans-Regular"),url(open-sans-latin-400.woff2) format("woff2")}@font-face{font-family:Open Sans;font-style:normal;font-display:swap;font-weight:700;src:local("Open Sans Bold "),local("Open Sans-Bold"),url(open-sans-latin-700.woff2) format("woff2")}.border-bottom,.border-left,.border-top,.relative{position:relative}.border-top:before{top:0}.border-bottom:after,.border-top:before{position:absolute;content:"";height:1px;width:100%;transform:scaleY(.5) translateZ(0);left:0;right:0;background:#555}.border-bottom:after{bottom:0}.border-left:before{position:absolute;content:"";height:100%;width:1px;transform:scaleX(.5) translateZ(0);top:0;bottom:0;background:#555;left:0}*,:after,:before{box-sizing:border-box}:root{--font-mono:"Roboto Mono",Menlo,monospace;--font-normal:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,"PingFang SC","Microsoft YaHei","微软雅黑",Arial,sans-serif;--color-focus-blue:#1a73e8}body{font-family:Open Sans,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,PingFang SC,Microsoft YaHei,微软雅黑;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;margin:0;padding:0}body,body.dark{--color-background:#202020;--color-text:#ddd;--color-text-secondary:#ccc;--color-text-highlight:#fff;--color-bg-sidebar:#2d2d30;--color-sb-active-row-bg:#494b4e;--color-input-bg:#2d2d30;--color-input-border:#3f3f3f;--color-toggle-bg:#353535;--color-toggle-selected:#181818;--color-icon:#c7c7c7;--color-separator:#333;--color-btn-bg:#232323;--color-btn-fg:#bebebe;--color-bg-proxy:#303030;--color-row-odd:#282828;--bg-modal:#1f1f20;--bg-near-transparent:hsla(0,0%,100%,0.1);--select-border-color:#040404;--select-bg-hover:url("data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 7l3 4H1l3-4zM4 17l-3-4h6l-3 4z' fill='%23fff'/%3E%3C/svg%3E")}body.light{--color-background:#fbfbfb;--color-text:#222;--color-text-secondary:#646464;--color-text-highlight:#040404;--color-bg-sidebar:#e7e7e7;--color-sb-active-row-bg:#d0d0d0;--color-input-bg:#fff;--color-input-border:silver;--color-toggle-bg:#fff;--color-toggle-selected:#d7d7d7;--color-icon:#5b5b5b;--color-separator:#ccc;--color-btn-bg:#f4f4f4;--color-btn-fg:#101010;--color-bg-proxy:#e7e7e7;--color-row-odd:#f5f5f5;--bg-modal:#fbfbfb;--bg-near-transparent:rgba(0,0,0,0.1);--select-border-color:#999;--select-bg-hover:url("data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 7l3 4H1l3-4zM4 17l-3-4h6l-3 4z' fill='%23222'/%3E%3C/svg%3E")}.flexCenter{display:flex;align-items:center;justify-content:center}.fabgrp{position:fixed;z-index:3;right:20px;bottom:20px}
|
||||
._73r9mFp69q{display:grid;grid-template-columns:repeat(11,minmax(-webkit-max-content,auto));grid-template-columns:repeat(11,minmax(max-content,auto))}.hEAcjybq1r{padding:8px 10px;height:50px;background:var(--color-background);position:-webkit-sticky;position:sticky;top:0;font-size:.8em;text-align:center;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;align-items:center;justify-content:space-between}.hEAcjybq1r:hover{color:var(--color-text-highlight)}._1x7JSEXzR8{padding:8px 13px;font-size:.9em;font-family:var(--font-normal)}._1x7JSEXzR8._3n5sGVMC-F{background:var(--color-row-odd)}._26SQDJZWya{text-align:right}._3LKH-WXUjR{display:inline-flex;margin-left:10px;width:16px;height:16px}._1CoVX1S_So{transform:rotate(180deg)}
|
||||
._3R-iKwDVj-{background-color:rgba(0,0,0,.6)}._1vh9rFTHqn{background-color:var(--bg-modal);color:var(--color-text);max-width:300px;line-height:1.4;transform:translate(-50%,-50%) scale(1.2);opacity:.6;transition:all .3s ease}._3bTCBReMiZ{opacity:1;transform:translate(-50%,-50%) scale(1)}._1lwetyauPD{display:flex;align-items:center;justify-content:center;margin-top:30px}
|
||||
.rtf{box-sizing:border-box;margin:25px;position:fixed;white-space:nowrap;z-index:9998;padding-left:0;list-style:none}.rtf.open .rtf--mb>*{transition:transform .2s ease-in-out}.rtf.open .rtf--mb{background:rgba(56,124,236,.92);box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.rtf.open .rtf--mb>ul{list-style:none;margin:0;padding:0}.rtf.open .rtf--ab__c:hover>span,.rtf.open .rtf--ab__c>span.always-show{transition:opacity .2s ease-in-out;opacity:.9}.rtf.open .rtf--ab__c:first-child{transform:translateY(-60px) scale(1);transition-delay:.03s}.rtf.open .rtf--ab__c:first-child.top{transform:translateY(60px) scale(1)}.rtf.open .rtf--ab__c:nth-child(2){transform:translateY(-120px) scale(1);transition-delay:.09s}.rtf.open .rtf--ab__c:nth-child(2).top{transform:translateY(120px) scale(1)}.rtf.open .rtf--ab__c:nth-child(3){transform:translateY(-180px) scale(1);transition-delay:.12s}.rtf.open .rtf--ab__c:nth-child(3).top{transform:translateY(180px) scale(1)}.rtf.open .rtf--ab__c:nth-child(4){transform:translateY(-240px) scale(1);transition-delay:.15s}.rtf.open .rtf--ab__c:nth-child(4).top{transform:translateY(240px) scale(1)}.rtf.open .rtf--ab__c:nth-child(5){transform:translateY(-300px) scale(1);transition-delay:.18s}.rtf.open .rtf--ab__c:nth-child(5).top{transform:translateY(300px) scale(1)}.rtf.open .rtf--ab__c:nth-child(6){transform:translateY(-360px) scale(1);transition-delay:.21s}.rtf.open .rtf--ab__c:nth-child(6).top{transform:translateY(360px) scale(1)}.rtf--mb__c{padding:25px;margin:-25px}.rtf--mb__c :last-child{margin-bottom:0}.rtf--mb__c:hover>span,.rtf--mb__c>span.always-show{transition:opacity .2s ease-in-out;opacity:.9}.rtf--mb__c>span{opacity:0;transition:opacity .2s ease-in-out;position:absolute;top:50%;transform:translateY(-50%);margin-right:6px;margin-left:4px;background:rgba(0,0,0,.75);padding:2px 4px;border-radius:2px;color:#fff;font-size:13px;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28)}.rtf--mb__c>span.right{right:100%}.rtf--mb{height:48px;width:48px;z-index:9999;background:#387cec;display:inline-flex;justify-content:center;align-items:center;position:relative;border:none;border-radius:50%;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28);cursor:pointer;outline:none;padding:0;-webkit-user-drag:none;font-weight:700;color:#f1f1f1;font-size:18px}.rtf--ab__c,.rtf--mb>*{transition:transform .2s ease-in-out}.rtf--ab__c{display:block;position:absolute;top:0;right:1px;padding:10px 0;margin:-10px 0}.rtf--ab__c>span{opacity:0;transition:opacity .2s ease-in-out;position:absolute;top:50%;transform:translateY(-50%);margin-right:6px;background:rgba(0,0,0,.75);padding:2px 4px;border-radius:2px;color:#fff;font-size:13px;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28)}.rtf--ab__c>span.right{right:100%}.rtf--ab__c:first-child{transform:translateY(-60px) scale(0);transition-delay:.21s}.rtf--ab__c:first-child.top{transform:translateY(60px) scale(0)}.rtf--ab__c:nth-child(2){transform:translateY(-120px) scale(0);transition-delay:.18s}.rtf--ab__c:nth-child(2).top{transform:translateY(120px) scale(0)}.rtf--ab__c:nth-child(3){transform:translateY(-180px) scale(0);transition-delay:.15s}.rtf--ab__c:nth-child(3).top{transform:translateY(180px) scale(0)}.rtf--ab__c:nth-child(4){transform:translateY(-240px) scale(0);transition-delay:.12s}.rtf--ab__c:nth-child(4).top{transform:translateY(240px) scale(0)}.rtf--ab__c:nth-child(5){transform:translateY(-300px) scale(0);transition-delay:.09s}.rtf--ab__c:nth-child(5).top{transform:translateY(300px) scale(0)}.rtf--ab__c:nth-child(6){transform:translateY(-360px) scale(0);transition-delay:.03s}.rtf--ab__c:nth-child(6).top{transform:translateY(360px) scale(0)}.rtf--ab{height:40px;width:40px;margin-right:4px;background-color:#aaa;display:inline-flex;justify-content:center;align-items:center;position:relative;border:none;border-radius:50%;box-shadow:0 0 4px rgba(0,0,0,.14),0 4px 8px rgba(0,0,0,.28);cursor:pointer;outline:none;padding:0;-webkit-user-drag:none;font-weight:700;color:#f1f1f1;font-size:16px;z-index:10000}.rtf--ab:hover{background:#387cec;border:1px solid #387cec;color:#fff}.rtf--ab:focus{border-color:var(--color-focus-blue)}
|
||||
._1rJPiLWN4s{position:fixed;top:0;bottom:0;left:0;right:0;overflow:hidden;padding:20px;background:var(--color-background);color:var(--color-text);text-align:center}._3h_IywJG1l{color:#2a477a;opacity:.6;display:flex;justify-content:center;padding:40px}.aXXDDfyTjE,._3h_IywJG1l{align-items:center}.aXXDDfyTjE{display:inline-flex;color:var(--color-text-secondary)}.aXXDDfyTjE:active,.aXXDDfyTjE:hover{color:#387cec}.aXXDDfyTjE svg{margin-right:5px}
|
||||
._2rN7aLQPCl{padding:6px 15px}@media screen and (min-width:30em){._2rN7aLQPCl{padding:10px 40px}}
|
||||
._1EnK5MMInH{width:100%;height:100%;display:flex;justify-content:center;align-items:center}._39z9L5I2ao{--color1:#ddd;--size:40px;width:var(--size);height:var(--size);margin:10px;background-color:var(--color1);border-radius:100%;animation:_1DSWK2a-pe 1s ease-in-out infinite}@keyframes _1DSWK2a-pe{0%{transform:scale(0)}to{transform:scale(1);opacity:0}}
|
||||
._37kQcxVR4T{color:var(--color-text);display:flex;align-items:center;flex-wrap:wrap}._37kQcxVR4T .sec{padding:10px;width:180px}._37kQcxVR4T .sec div:first-child{color:var(--color-text-secondary);font-size:.7em}._37kQcxVR4T .sec div:nth-child(2){padding:10px 0 0;font-size:1.8em}
|
||||
._3oi0NFbeOm{opacity:.5;width:100%;height:100%;display:flex;justify-content:center;align-items:center}
|
||||
._2tpN_G7FeO{display:flex;align-items:center;flex-wrap:wrap;font-size:.9em;padding:10px}._3wuPHKqO5W{color:#eee;flex-shrink:0;text-align:center;width:66px;background:green;border-radius:5px;padding:3px 5px;margin:0 8px}.IwiVCclCSC{flex-shrink:0;color:#999;font-size:14px}._3I1beKAMFt{flex-shrink:0;display:flex;font-family:Roboto Mono,Menlo,monospace;align-items:center;padding:8px 0;width:100%;white-space:pre;overflow:auto}._2MDNI6JESq{margin:0;padding:0;color:var(--color-text)}._2MDNI6JESq li,._2MDNI6JESq li.even{background:var(--color-background)}._3KX1sKJ1QD{padding:10px 40px}._19_8g6kTIV{display:flex;flex-direction:column;align-items:center;justify-content:center;color:#2d2d30}._19_8g6kTIV div:nth-child(2){color:var(--color-text-secondary);font-size:1.4em;opacity:.6}._3ljFcrWmBC{opacity:.3}
|
||||
._1u5AP7XMF9{padding:0 40px 5px}._2zeyKJDdFH{position:relative;height:40px}._3DQ7SXxKRA{position:absolute;top:50%;transform:translateY(-50%);left:0;width:100%}._1f-XUgRxH1{-webkit-appearance:none;background-color:var(--color-input-bg);background-image:none;border-radius:20px;border:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;height:40px;outline:none;padding:0 15px 0 35px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}._3PLtWxZwrd{position:absolute;top:50%;transform:translateY(-50%);left:10px}
|
||||
._35EMVy62Je{display:flex;background:var(--color-background);color:var(--color-text);min-height:300px;height:100vh}@media (max-width:768px){._35EMVy62Je{flex-direction:column}}.AwL8oIubvP{flex-grow:1;overflow:auto}
|
||||
._30oJwXNik9{background:var(--color-bg-sidebar);position:relative}._1SsCcpJvxN{display:block}._2r8EkOI78X{display:flex;align-items:center;justify-content:center;padding:25px 0 15px;color:#2a477a;transition:color .3s ease-in-out}@media (max-width:768px){._2r8EkOI78X{display:none}}._2r8EkOI78X:hover{animation:_2KRqAfqV8c .3s ease-in-out 0s infinite alternate}._2r8EkOI78X img{width:80px;height:80px}@keyframes _2KRqAfqV8c{0%{color:#2a477a}to{color:#1f52ac}}@media (max-width:768px){._2vUQ0Hs_C5{display:flex;justify-content:space-between;overflow:scroll}}._8mEn9Wlw1n{color:var(--color-text);text-decoration:none;display:flex;align-items:center;padding:6px 16px}@media screen and (min-width:30em){._8mEn9Wlw1n{padding:8px 20px}}@media (max-width:768px){._8mEn9Wlw1n{flex-direction:column}}._8mEn9Wlw1n svg{color:var(--color-icon);width:22px;height:22px}@media screen and (min-width:30em){._8mEn9Wlw1n svg{width:24px;height:24px}}._1WyHmd6t6y{background:var(--color-sb-active-row-bg)}@media (max-width:768px){._1WyHmd6t6y{background:none;border-bottom:2px solid #387cec}}._2eMIYGbP9O{padding-left:14px;font-size:.75em}@media (max-width:768px){._2eMIYGbP9O{padding-left:0;padding-top:5px}}@media screen and (min-width:30em){._2eMIYGbP9O{font-size:1em}}.nURY8qkFLS{--sz:40px;position:absolute;bottom:10px;left:50%;transform:translateX(-50%);width:var(--sz);height:var(--sz);display:flex;justify-content:center;align-items:center;color:var(--color-text);padding:5px;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;background:none;cursor:pointer;border:1px solid transparent;border-radius:100%}@media (max-width:768px){.nURY8qkFLS{display:none}}.nURY8qkFLS:focus{border-color:var(--color-focus-blue)}
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"><link rel="shortcut icon" href="yacd.ico"><link rel="icon" type="image/png" sizes="64x64" href="yacd-64.png"><link rel="icon" type="image/png" sizes="128x128" href="yacd-128.png"><link rel="preload" href="/open-sans-latin-400.woff2" as="font"><link rel="preload" href="/open-sans-latin-700.woff2" as="font"><link rel="preload" href="/roboto-mono-latin-400.woff2" as="font"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="application-name" content="yacd"><meta name="description" content="Yet Another Clash Dashboard"><meta name="theme-color" content="#202020"><title>yacd - Yet Another Clash Dashboard</title><meta property="og:image" content="https://user-images.githubusercontent.com/1166872/47304841-536f3d80-d65a-11e8-8908-1917127dafc5.png"><meta property="og:site_name" content="yacd"><meta property="og:type" content="object"><meta property="og:title" content="yacd"><meta property="og:url" content="http://yacd.haishan.me"><meta property="og:description" content="Yet Another Clash Dashboard"><script defer="defer" src="runtime.37e8203ec536250e1e4c.js"></script><script defer="defer" src="core-js~app.f925e7b0d7db8cb56360.js"></script><script defer="defer" src="react~app.11ff7e45a0d5e0bfa30d.js"></script><script defer="defer" src="app.2ba50fd5acdb533fac49.js"></script><link href="app.8ff5510a4335f1c96a7c.css" rel="stylesheet"></head><body><div id="app"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"><link rel="shortcut icon" href="yacd.ico"><link rel="icon" type="image/png" sizes="64x64" href="yacd-64.png"><link rel="icon" type="image/png" sizes="128x128" href="yacd-128.png"><link rel="preload" href="/open-sans-latin-400.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="/open-sans-latin-700.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="/roboto-mono-latin-400.woff2" as="font" type="font/woff2" crossorigin><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="application-name" content="yacd"><meta name="description" content="Yet Another Clash Dashboard"><meta name="theme-color" content="#202020"><title>yacd - Yet Another Clash Dashboard</title><meta property="og:image" content="https://user-images.githubusercontent.com/1166872/47304841-536f3d80-d65a-11e8-8908-1917127dafc5.png"><meta property="og:site_name" content="yacd"><meta property="og:type" content="object"><meta property="og:title" content="yacd"><meta property="og:url" content="http://yacd.haishan.me"><meta property="og:description" content="Yet Another Clash Dashboard"><script defer="defer" src="runtime.2f322c031bcb67b98af2.js"></script><script defer="defer" src="core-js~app.36c6f0077ac1e602b325.js"></script><script defer="defer" src="react~app.10618449a8e9b56a1845.js"></script><script defer="defer" src="app.09d100e5dacbf4f76606.js"></script><link href="app.b814d6460bc4d015f5f9.css" rel="stylesheet"></head><body><div id="app"></div></body></html>
|
||||
@@ -1,11 +1,12 @@
|
||||
._37wt2_a2Gx{display:flex;align-items:center}._37wt2_a2Gx .L80zPM0Rx0{display:inline-flex;transform:rotate(0deg);transition:transform .3s}._37wt2_a2Gx .L80zPM0Rx0._36RO7_wtuv{transform:rotate(180deg)}._37wt2_a2Gx .L80zPM0Rx0:focus{outline:var(--color-focus-blue) solid 1px}._2XKN3NArpV{margin-left:5px}._1s98xvUoBx{font-family:var(--font-normal);font-size:.75em;margin-left:3px;padding:2px 7px;display:inline-flex;justify-content:center;align-items:center;background-color:var(--bg-near-transparent);border-radius:30px}
|
||||
._2tHS8vcjWZ{border-radius:20px;color:#eee;font-size:.6em}@media screen and (min-width:30em){._2tHS8vcjWZ{font-size:1em}}
|
||||
._1OypGPFF1I{margin:3px;padding:5px;position:relative;border-radius:8px;overflow:hidden;display:flex;flex-direction:column;justify-content:space-between;max-width:280px;background-color:var(--color-bg-proxy)}@media screen and (min-width:30em){._1OypGPFF1I{min-width:200px;border-radius:10px;padding:10px}}._1OypGPFF1I._25Vy0R3DBh{background-color:var(--color-focus-blue);color:#ddd}._1OypGPFF1I._20b8CxdJZg{opacity:.5}._1OypGPFF1I._2jncDUnzU1{transition:transform .2s ease-in-out;cursor:pointer}._1OypGPFF1I._2jncDUnzU1:hover{transform:translateY(-2px)}._3ILPKOrew2{font-family:var(--font-mono);font-size:.6em}@media screen and (min-width:30em){._3ILPKOrew2{font-size:1em}}._3DtTZsIYVP{display:flex;align-items:center;justify-content:space-between}._2dGvkUlaDx{width:100%;margin-bottom:5px;font-size:.85em}@media screen and (min-width:30em){._2dGvkUlaDx{font-size:1em}}._1fX-k2HS41{width:13px;height:13px;border-radius:50%;border:1px solid var(--color-background)}._1fX-k2HS41._25Vy0R3DBh{border-color:var(--color-text-secondary)}._1fX-k2HS41._2jncDUnzU1{transition:transform .1s ease-in-out;cursor:pointer}._1fX-k2HS41._2jncDUnzU1:hover{transform:scale(1.2)}
|
||||
._1Zy60rJawW{display:flex;flex-wrap:wrap;margin:8px 0 8px -3px}._1YJnElh2Sr{margin:8px 0;display:grid;grid-template-columns:repeat(auto-fill,13px);grid-gap:10px}
|
||||
.WqD74l0KeZ{margin-bottom:12px}._3u5R6urbB9{width:20px;height:20px;display:flex;align-items:center;justify-content:center}
|
||||
._2OKIZuCJtW{background-color:rgba(0,0,0,.6)}._1y6NeshM4O{position:absolute;background-color:var(--bg-modal);color:var(--color-text);line-height:1.4;opacity:.6;transition:all .3s ease;transform:translate(-50%,-50%) scale(1.2);box-shadow:0 4px 4px rgba(0,0,0,.12),0 16px 32px rgba(0,0,0,.24)}._25KARE4UsT{opacity:1;transform:translate(-50%,-50%) scale(1)}
|
||||
.W_0q0BiEOR{display:flex;justify-content:center;align-items:center}
|
||||
._1vpeUMroNJ{position:-webkit-sticky;position:sticky;top:0;justify-content:space-between;flex-wrap:wrap;z-index:1;background:var(--color-background);background:linear-gradient(var(--color-background) 70%,transparent)}._1vpeUMroNJ,.pGNJbFaunZ{display:flex;align-items:center}.pGNJbFaunZ{flex-wrap:wrap;flex:1;justify-content:flex-end;margin-right:20px}._1aJVGJw_DC{max-width:350px;min-width:150px;flex:1;margin-right:8px}._2gOPGelc7s{padding:10px 15px}@media screen and (min-width:30em){._2gOPGelc7s{padding:10px 40px}}._3BayoLOhA0{position:relative;border-radius:50%;background:linear-gradient(60deg,#e66465,#9198e5)}._3BayoLOhA0:before{content:"";position:absolute;top:0;bottom:0;left:0;right:0;border:2px solid transparent;border-top-color:initial;border-radius:50%;animation:NKvZlK5zKz 1s linear infinite}@keyframes NKvZlK5zKz{0%{transform:rotate(0)}to{transform:rotate(1turn)}}
|
||||
._37wt2_a2Gx{display:flex;align-items:center}._37wt2_a2Gx .L80zPM0Rx0{display:inline-flex;transform:rotate(0deg);transition:transform .3s}._37wt2_a2Gx .L80zPM0Rx0._36RO7_wtuv{transform:rotate(180deg)}._37wt2_a2Gx .L80zPM0Rx0:focus{outline:var(--color-focus-blue) solid 1px}._2XKN3NArpV{margin-left:5px}._1s98xvUoBx{font-family:var(--font-normal);font-size:.75em;margin-left:3px;padding:2px 7px;display:inline-flex;justify-content:center;align-items:center;background-color:var(--bg-near-transparent);border-radius:30px}
|
||||
.WqD74l0KeZ{margin-bottom:12px}._3u5R6urbB9{width:20px;height:20px;display:flex;align-items:center;justify-content:center}
|
||||
._1OypGPFF1I{margin:3px;padding:5px;position:relative;border-radius:8px;overflow:hidden;display:flex;flex-direction:column;justify-content:space-between;max-width:280px;background-color:var(--color-bg-proxy)}@media screen and (min-width:30em){._1OypGPFF1I{min-width:200px;border-radius:10px;padding:10px}}._1OypGPFF1I._25Vy0R3DBh{background-color:var(--color-focus-blue);color:#ddd}._1OypGPFF1I._20b8CxdJZg{opacity:.5}._1OypGPFF1I._2jncDUnzU1{transition:transform .2s ease-in-out;cursor:pointer}._1OypGPFF1I._2jncDUnzU1:hover{transform:translateY(-2px)}._3ILPKOrew2{font-family:var(--font-mono);font-size:.6em}@media screen and (min-width:30em){._3ILPKOrew2{font-size:1em}}._3DtTZsIYVP{display:flex;align-items:center;justify-content:space-between}._2dGvkUlaDx{width:100%;margin-bottom:5px;font-size:.85em}@media screen and (min-width:30em){._2dGvkUlaDx{font-size:1em}}._1fX-k2HS41{width:13px;height:13px;border-radius:50%;border:1px solid var(--color-background)}._1fX-k2HS41._25Vy0R3DBh{border-color:var(--color-text-secondary)}._1fX-k2HS41._2jncDUnzU1{transition:transform .1s ease-in-out;cursor:pointer}._1fX-k2HS41._2jncDUnzU1:hover{transform:scale(1.2)}
|
||||
._2tHS8vcjWZ{border-radius:20px;color:#eee;font-size:.6em}@media screen and (min-width:30em){._2tHS8vcjWZ{font-size:1em}}
|
||||
._1Zy60rJawW{display:flex;flex-wrap:wrap;margin:8px 0 8px -3px}._1YJnElh2Sr{margin:8px 0;display:grid;grid-template-columns:repeat(auto-fill,13px);grid-gap:10px}
|
||||
._2PJqMIeTLt{margin-bottom:12px}._2PJqMIeTLt small{color:#777}._2bdge0dkRf{padding:10px 15px}@media screen and (min-width:30em){._2bdge0dkRf{padding:10px 40px}}.Vp69gn8Y28{display:flex}.Vp69gn8Y28 button{margin:0 5px}.Vp69gn8Y28 button:first-child{margin-left:0}._32jty5m2Ss{display:flex;justify-content:center;align-items:center;cursor:pointer}
|
||||
.t6lsDKNXTK{height:30px;width:100%;padding-left:8px;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--color-background);color:var(--color-text);padding-right:20px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='8' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 7l3 4H1l3-4zM4 17l-3-4h6l-3 4z' fill='%23999'/%3E%3C/svg%3E");border-radius:4px;border-image:initial;border:1px solid var(--select-border-color);transition:all .1s ease 0s;background-position:calc(100% - 8px) 50%;background-repeat:no-repeat}.t6lsDKNXTK:focus,.t6lsDKNXTK:hover{border-color:#343434;outline:none!important;color:var(--color-text-highlight);background-image:var(--select-bg-hover)}.t6lsDKNXTK option{background-color:var(--color-background)}
|
||||
._1h4Qixiwxj{max-width:85vw;width:400px;display:flex;justify-content:space-between;align-items:center;font-size:13px;padding:13px 0}hr{height:1px;background-color:var(--color-separator);border:none;outline:none;margin:1rem 0}
|
||||
.W_0q0BiEOR{display:flex;justify-content:center;align-items:center}
|
||||
._2PJqMIeTLt{margin-bottom:12px}._2PJqMIeTLt small{color:#777}._2bdge0dkRf{padding:10px 15px}@media screen and (min-width:30em){._2bdge0dkRf{padding:10px 40px}}.Vp69gn8Y28{display:flex}.Vp69gn8Y28 button{margin:0 5px}.Vp69gn8Y28 button:first-child{margin-left:0}._32jty5m2Ss{display:flex;justify-content:center;align-items:center;cursor:pointer}
|
||||
._1vpeUMroNJ{position:-webkit-sticky;position:sticky;top:0;display:flex;align-items:center;justify-content:space-between;z-index:1;background:var(--color-background);background:linear-gradient(var(--color-background) 70%,transparent)}._2fxAc3OESk{margin-right:20px}._2gOPGelc7s{padding:10px 15px}@media screen and (min-width:30em){._2gOPGelc7s{padding:10px 40px}}._3BayoLOhA0{position:relative;border-radius:50%;background:linear-gradient(60deg,#e66465,#9198e5)}._3BayoLOhA0:before{content:"";position:absolute;top:0;bottom:0;left:0;right:0;border:2px solid transparent;border-top-color:initial;border-radius:50%;animation:NKvZlK5zKz 1s linear infinite}@keyframes NKvZlK5zKz{0%{transform:rotate(0)}to{transform:rotate(1turn)}}
|
||||
._1LsRPWba72{-webkit-appearance:none;background-color:var(--color-input-bg);background-image:none;border-radius:20px;border:1px solid var(--color-input-border);box-sizing:border-box;color:#c1c1c1;display:inline-block;font-size:inherit;outline:none;padding:8px 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}._1LsRPWba72:focus{border:1px solid var(--color-focus-blue)}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{BVyM:function(e,t,a){"use strict";a.r(t);var r=a("ODXe"),n=a("q1tI"),i=a.n(n),c=a("iR1w"),o=a("OAQO"),l=a("9cvt"),u=a("WfPo"),s=a("OADI"),f=a("DKqX"),p=a("17x9"),d=a.n(p),m=a("xrux"),v=a.n(m),b={_default:"#59caf9",DIRECT:"#f5bc41",REJECT:"#cb3166"};function y(e){var t=e.type,a=e.payload,r=e.proxy,n=e.id,c=function(e){var t=e.proxy,a=b._default;return b[t]&&(a=b[t]),{color:a}}({proxy:r});return i.a.createElement("div",{className:v.a.rule},i.a.createElement("div",{className:v.a.left},n),i.a.createElement("div",null,i.a.createElement("div",{className:v.a.b},a),i.a.createElement("div",{className:v.a.a},i.a.createElement("div",{className:v.a.type},t),i.a.createElement("div",{style:c},r))))}y.propTypes={id:d.a.number,type:d.a.string,payload:d.a.string,proxy:d.a.string};var O=y,E=a("II4a"),h=a("EwbC"),w=Object(u.a)((function(e){return{searchText:Object(h.d)(e),updateSearchText:h.f}}))(E.a),g=a("Kv4h"),x=i.a.memo,j=i.a.useEffect,k=i.a.useMemo,C=i.a.useCallback;function N(e,t){return t[e].id}var I=x((function(e){var t=e.index,a=e.style,r=e.data[t];return i.a.createElement("div",{style:a},i.a.createElement(O,r))}),c.b);t.default=Object(u.a)((function(e){return{apiConfig:Object(s.c)(e),rules:Object(h.c)(e)}}))((function(e){var t=e.dispatch,a=e.apiConfig,n=e.rules,u=C((function(){t(Object(h.a)(a))}),[a,t]);j((function(){t(Object(h.b)(a))}),[t,a]);var s=Object(g.a)(),p=Object(r.a)(s,2),d=p[0],m=p[1],v=k((function(){return i.a.createElement(o.a,{width:16})}),[]);return i.a.createElement("div",null,i.a.createElement(f.a,{title:"Rules"}),i.a.createElement(w,null),i.a.createElement("div",{ref:d,style:{paddingBottom:30}},i.a.createElement(c.a,{height:m-30,width:"100%",itemCount:n.length,itemSize:80,itemData:n,itemKey:N},I)),i.a.createElement(l.b,{icon:v,text:"Refresh",onClick:u,position:l.c}))}))},OAQO:function(e,t,a){"use strict";var r=a("q1tI"),n=a.n(r),i=a("17x9"),c=a.n(i);function o(){return(o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var r in a)Object.prototype.hasOwnProperty.call(a,r)&&(e[r]=a[r])}return e}).apply(this,arguments)}function l(e,t){if(null==e)return{};var a,r,n=function(e,t){if(null==e)return{};var a,r,n={},i=Object.keys(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var u=Object(r.forwardRef)((function(e,t){var a=e.color,r=void 0===a?"currentColor":a,i=e.size,c=void 0===i?24:i,u=l(e,["color","size"]);return n.a.createElement("svg",o({ref:t,xmlns:"http://www.w3.org/2000/svg",width:c,height:c,viewBox:"0 0 24 24",fill:"none",stroke:r,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"},u),n.a.createElement("polyline",{points:"23 4 23 10 17 10"}),n.a.createElement("path",{d:"M20.49 15a9 9 0 1 1-2.12-9.36L23 10"}))}));u.propTypes={color:c.a.string,size:c.a.oneOfType([c.a.string,c.a.number])},u.displayName="RotateCw",t.a=u},xrux:function(e,t,a){e.exports={rule:"_3eSLieOhVX",left:"_2n1pW09UvV",a:"t1XJIwvW7A",b:"_1fNf8kj0HA",type:"_3yJmN0tON0"}}}]);
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{BVyM:function(e,t,a){"use strict";a.r(t);var r=a("ODXe"),n=a("q1tI"),i=a.n(n),c=a("OAQO"),o=a("iR1w"),l=a("Kv4h"),u=a("OADI"),s=a("EwbC"),f=a("DKqX"),p=a("17x9"),d=a.n(p),m=a("xrux"),v=a.n(m),b={_default:"#59caf9",DIRECT:"#f5bc41",REJECT:"#cb3166"};function y(e){var t=e.type,a=e.payload,r=e.proxy,n=e.id,c=function(e){var t=e.proxy,a=b._default;return b[t]&&(a=b[t]),{color:a}}({proxy:r});return i.a.createElement("div",{className:v.a.rule},i.a.createElement("div",{className:v.a.left},n),i.a.createElement("div",null,i.a.createElement("div",{className:v.a.b},a),i.a.createElement("div",{className:v.a.a},i.a.createElement("div",{className:v.a.type},t),i.a.createElement("div",{style:c},r))))}y.propTypes={id:d.a.number,type:d.a.string,payload:d.a.string,proxy:d.a.string};var O=y,E=a("II4a"),h=a("WfPo"),w=Object(h.a)((function(e){return{searchText:Object(s.d)(e),updateSearchText:s.f}}))(E.a),g=a("9cvt"),x=i.a.memo,j=i.a.useEffect,k=i.a.useMemo,C=i.a.useCallback;function N(e,t){return t[e].id}var I=x((function(e){var t=e.index,a=e.style,r=e.data[t];return i.a.createElement("div",{style:a},i.a.createElement(O,r))}),o.b);t.default=Object(h.a)((function(e){return{apiConfig:Object(u.c)(e),rules:Object(s.c)(e)}}))((function(e){var t=e.dispatch,a=e.apiConfig,n=e.rules,u=C((function(){t(Object(s.a)(a))}),[a,t]);j((function(){t(Object(s.b)(a))}),[t,a]);var p=Object(l.a)(),d=Object(r.a)(p,2),m=d[0],v=d[1],b=k((function(){return i.a.createElement(c.a,{width:16})}),[]);return i.a.createElement("div",null,i.a.createElement(f.a,{title:"Rules"}),i.a.createElement(w,null),i.a.createElement("div",{ref:m,style:{paddingBottom:30}},i.a.createElement(o.a,{height:v-30,width:"100%",itemCount:n.length,itemSize:80,itemData:n,itemKey:N},I)),i.a.createElement(g.b,{icon:b,text:"Refresh",onClick:u,position:g.c}))}))},OAQO:function(e,t,a){"use strict";var r=a("q1tI"),n=a.n(r),i=a("17x9"),c=a.n(i);function o(){return(o=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var r in a)Object.prototype.hasOwnProperty.call(a,r)&&(e[r]=a[r])}return e}).apply(this,arguments)}function l(e,t){if(null==e)return{};var a,r,n=function(e,t){if(null==e)return{};var a,r,n={},i=Object.keys(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var u=Object(r.forwardRef)((function(e,t){var a=e.color,r=void 0===a?"currentColor":a,i=e.size,c=void 0===i?24:i,u=l(e,["color","size"]);return n.a.createElement("svg",o({ref:t,xmlns:"http://www.w3.org/2000/svg",width:c,height:c,viewBox:"0 0 24 24",fill:"none",stroke:r,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"},u),n.a.createElement("polyline",{points:"23 4 23 10 17 10"}),n.a.createElement("path",{d:"M20.49 15a9 9 0 1 1-2.12-9.36L23 10"}))}));u.propTypes={color:c.a.string,size:c.a.oneOfType([c.a.string,c.a.number])},u.displayName="RotateCw",t.a=u},xrux:function(e,t,a){e.exports={rule:"_3eSLieOhVX",left:"_2n1pW09UvV",a:"t1XJIwvW7A",b:"_1fNf8kj0HA",type:"_3yJmN0tON0"}}}]);
|
||||
@@ -1 +1 @@
|
||||
!function(e){function t(t){for(var n,o,i=t[0],l=t[1],s=t[2],f=t[3]||[],d=0,h=[];d<i.length;d++)o=i[d],Object.prototype.hasOwnProperty.call(a,o)&&a[o]&&h.push(a[o][0]),a[o]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t),c.push.apply(c,f);h.length;)h.shift()();return u.push.apply(u,s||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,o=1;o<r.length;o++){var s=r[o];0!==a[s]&&(n=!1)}n&&(u.splice(t--,1),e=l(l.s=r[0]))}return 0===u.length&&(c.forEach((function(e){if(void 0===a[e]){a[e]=null;var t=document.createElement("link");l.nc&&t.setAttribute("nonce",l.nc),t.rel="prefetch",t.as="script",t.href=i(e),document.head.appendChild(t)}})),c.length=0),e}var n={},o={5:0},a={5:0},u=[],c=[];function i(e){return l.p+""+({2:"proxies",4:"rules",6:"vendors~chartjs",7:"vendors~proxies"}[e]||e)+"."+{2:"6a0a58d936ddbebbba53",4:"9bb11b1b25fa6817b033",6:"236a69375b65655cd7e6",7:"a3e2ad41949ba3aa37c4",8:"57c375f07ca41659ac12"}[e]+".js"}function l(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.e=function(e){var t=[];o[e]?t.push(o[e]):0!==o[e]&&{2:1,4:1}[e]&&t.push(o[e]=new Promise((function(t,r){for(var n=({2:"proxies",4:"rules",6:"vendors~chartjs",7:"vendors~proxies"}[e]||e)+"."+{2:"30780ebe14695af063e3",4:"664f8b737878361937cb",6:"31d6cfe0d16ae931b73c",7:"31d6cfe0d16ae931b73c",8:"31d6cfe0d16ae931b73c"}[e]+".css",a=l.p+n,u=document.getElementsByTagName("link"),c=0;c<u.length;c++){var i=(f=u[c]).getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(i===n||i===a))return t()}var s=document.getElementsByTagName("style");for(c=0;c<s.length;c++){var f;if((i=(f=s[c]).getAttribute("data-href"))===n||i===a)return t()}var d=document.createElement("link");d.rel="stylesheet",d.type="text/css",d.onload=t,d.onerror=function(t){var n=t&&t.target&&t.target.src||a,u=new Error("Loading CSS chunk "+e+" failed.\n("+n+")");u.code="CSS_CHUNK_LOAD_FAILED",u.request=n,delete o[e],d.parentNode.removeChild(d),r(u)},d.href=a,document.getElementsByTagName("head")[0].appendChild(d)})).then((function(){o[e]=0})));var r=a[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=a[e]=[t,n]}));t.push(r[2]=n);var u,c=document.createElement("script");c.charset="utf-8",c.timeout=120,l.nc&&c.setAttribute("nonce",l.nc),c.src=i(e);var s=new Error;u=function(t){c.onerror=c.onload=null,clearTimeout(f);var r=a[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;s.message="Loading chunk "+e+" failed.\n("+n+": "+o+")",s.name="ChunkLoadError",s.type=n,s.request=o,r[1](s)}a[e]=void 0}};var f=setTimeout((function(){u({type:"timeout",target:c})}),12e4);c.onerror=c.onload=u,document.head.appendChild(c)}return Promise.all(t)},l.m=e,l.c=n,l.d=function(e,t,r){l.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,t){if(1&t&&(e=l(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(l.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)l.d(r,n,function(t){return e[t]}.bind(null,n));return r},l.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(t,"a",t),t},l.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},l.p="",l.oe=function(e){throw console.error(e),e};var s=window.webpackJsonp=window.webpackJsonp||[],f=s.push.bind(s);s.push=t,s=s.slice();for(var d=0;d<s.length;d++)t(s[d]);var p=f;r()}([]);
|
||||
!function(e){function t(t){for(var n,o,i=t[0],l=t[1],d=t[2],f=t[3]||[],s=0,h=[];s<i.length;s++)o=i[s],Object.prototype.hasOwnProperty.call(a,o)&&a[o]&&h.push(a[o][0]),a[o]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(t),c.push.apply(c,f);h.length;)h.shift()();return u.push.apply(u,d||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,o=1;o<r.length;o++){var d=r[o];0!==a[d]&&(n=!1)}n&&(u.splice(t--,1),e=l(l.s=r[0]))}return 0===u.length&&(c.forEach((function(e){if(void 0===a[e]){a[e]=null;var t=document.createElement("link");l.nc&&t.setAttribute("nonce",l.nc),t.rel="prefetch",t.as="script",t.href=i(e),document.head.appendChild(t)}})),c.length=0),e}var n={},o={5:0},a={5:0},u=[],c=[];function i(e){return l.p+""+({2:"proxies",4:"rules",6:"vendors~chartjs",7:"vendors~proxies"}[e]||e)+"."+{2:"77fef0018a8d1766e6eb",4:"efd650d64b4afda8d49b",6:"e4543f10556636d64b75",7:"34b4cb2526b2e8ed766c",8:"872bd111e9c497e7acca"}[e]+".js"}function l(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,l),r.l=!0,r.exports}l.e=function(e){var t=[];o[e]?t.push(o[e]):0!==o[e]&&{2:1,4:1}[e]&&t.push(o[e]=new Promise((function(t,r){for(var n=({2:"proxies",4:"rules",6:"vendors~chartjs",7:"vendors~proxies"}[e]||e)+"."+{2:"1e31d885e6fe278da534",4:"664f8b737878361937cb",6:"31d6cfe0d16ae931b73c",7:"31d6cfe0d16ae931b73c",8:"31d6cfe0d16ae931b73c"}[e]+".css",a=l.p+n,u=document.getElementsByTagName("link"),c=0;c<u.length;c++){var i=(f=u[c]).getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(i===n||i===a))return t()}var d=document.getElementsByTagName("style");for(c=0;c<d.length;c++){var f;if((i=(f=d[c]).getAttribute("data-href"))===n||i===a)return t()}var s=document.createElement("link");s.rel="stylesheet",s.type="text/css",s.onload=t,s.onerror=function(t){var n=t&&t.target&&t.target.src||a,u=new Error("Loading CSS chunk "+e+" failed.\n("+n+")");u.code="CSS_CHUNK_LOAD_FAILED",u.request=n,delete o[e],s.parentNode.removeChild(s),r(u)},s.href=a,document.getElementsByTagName("head")[0].appendChild(s)})).then((function(){o[e]=0})));var r=a[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=a[e]=[t,n]}));t.push(r[2]=n);var u,c=document.createElement("script");c.charset="utf-8",c.timeout=120,l.nc&&c.setAttribute("nonce",l.nc),c.src=i(e);var d=new Error;u=function(t){c.onerror=c.onload=null,clearTimeout(f);var r=a[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;d.message="Loading chunk "+e+" failed.\n("+n+": "+o+")",d.name="ChunkLoadError",d.type=n,d.request=o,r[1](d)}a[e]=void 0}};var f=setTimeout((function(){u({type:"timeout",target:c})}),12e4);c.onerror=c.onload=u,document.head.appendChild(c)}return Promise.all(t)},l.m=e,l.c=n,l.d=function(e,t,r){l.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,t){if(1&t&&(e=l(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(l.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)l.d(r,n,function(t){return e[t]}.bind(null,n));return r},l.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(t,"a",t),t},l.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},l.p="",l.oe=function(e){throw console.error(e),e};var d=window.webpackJsonp=window.webpackJsonp||[],f=d.push.bind(d);d.push=t,d=d.slice();for(var s=0;s<d.length;s++)t(d[s]);var p=f;r()}([]);
|
||||
File diff suppressed because one or more lines are too long
@@ -645,12 +645,6 @@ cat >> "$SERVER_FILE" <<-EOF
|
||||
- Proxy
|
||||
- DIRECT
|
||||
- Domestic
|
||||
- name: AdBlock
|
||||
type: select
|
||||
proxies:
|
||||
- REJECT
|
||||
- DIRECT
|
||||
- Proxy
|
||||
- name: AsianTV
|
||||
type: select
|
||||
proxies:
|
||||
|
||||
@@ -106,7 +106,7 @@ if [ "$2" != 0 ]; then
|
||||
if [ -z "$(grep "$GlobalTV" /tmp/Proxy_Group)" ]\
|
||||
|| [ -z "$(grep "$AsianTV" /tmp/Proxy_Group)" ]\
|
||||
|| [ -z "$(grep "$Proxy" /tmp/Proxy_Group)" ]\
|
||||
|| [ -z "$(grep "$AdBlock" /tmp/Proxy_Group)" ]\
|
||||
# || [ -z "$(grep "$AdBlock" /tmp/Proxy_Group)" ]\
|
||||
|| [ -z "$(grep "$Others" /tmp/Proxy_Group)" ]\
|
||||
|| [ -z "$(grep "$Domestic" /tmp/Proxy_Group)" ]; then
|
||||
echo "${1} Warning: Because of The Different Porxy-Group's Name, Stop Setting The Other Rules!" >>/tmp/openclash.log
|
||||
@@ -188,7 +188,7 @@ if [ "$2" != 0 ]; then
|
||||
if [ "$GlobalTV" != "$GlobalTV_YAML" ]\
|
||||
|| [ "$AsianTV" != "$AsianTV_YAML" ]\
|
||||
|| [ "$Proxy" != "$Proxy_YAML" ]\
|
||||
|| [ "$AdBlock" != "$AdBlock_YAML" ]\
|
||||
# || [ "$AdBlock" != "$AdBlock_YAML" ]\
|
||||
|| [ "$Others" != "$Others_YAML" ]\
|
||||
|| [ "$Domestic" != "$Domestic_YAML" ]; then
|
||||
check_def=1
|
||||
@@ -298,9 +298,9 @@ if [ "$2" != 0 ]; then
|
||||
sed -i "s/,CN,DIRECT$/,China,${Domestic}#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "s/,CN,DIRECT,no-resolve$/,China,${Domestic},no-resolve#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "/rules:/a\##Domestic:${Domestic}" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "s/,Unbreak,DIRECT$/,Unbreak,${AdBlock}#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "s/,Unbreak,DIRECT,no-resolve$/,Unbreak,${AdBlock},no-resolve#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "/rules:/a\##Others:${AdBlock}" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
#sed -i "s/,Unbreak,DIRECT$/,Unbreak,${AdBlock}#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
#sed -i "s/,Unbreak,DIRECT,no-resolve$/,Unbreak,${AdBlock},no-resolve#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
#sed -i "/rules:/a\##AdBlock:${AdBlock}" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "s/,MATCH$/,${Others}#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "s/,MATCH,no-resolve$/,${Others},no-resolve#d/g" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
sed -i "/rules:/a\##Others:${Others}" "/tmp/other_rule.yaml" 2>/dev/null
|
||||
|
||||
@@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Argon Theme
|
||||
LUCI_DEPENDS:=
|
||||
PKG_VERSION:=1.5.2
|
||||
PKG_RELEASE:=01-2020401
|
||||
PKG_VERSION:=1.5.3
|
||||
PKG_RELEASE:=01-20200703
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
|
||||
@@ -511,7 +511,7 @@ footer>a {
|
||||
}
|
||||
|
||||
#maincontent>.container>p {
|
||||
color: #fff;
|
||||
color: #32325d;
|
||||
}
|
||||
|
||||
li {
|
||||
@@ -1500,7 +1500,7 @@ header {
|
||||
header::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
height: 14rem;
|
||||
height: 2.4rem;
|
||||
width: 100%;
|
||||
background-color: #5e72e4 !important;
|
||||
}
|
||||
@@ -1946,7 +1946,7 @@ div>.table>.tbody>.tr:nth-of-type(2n) {
|
||||
|
||||
header>.fill {
|
||||
padding: 0.8rem 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, .08) !important;
|
||||
border-bottom: 0px solid rgba(255, 255, 255, .08) !important;
|
||||
|
||||
}
|
||||
|
||||
@@ -2035,9 +2035,13 @@ h1 {
|
||||
h2 {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.5rem;
|
||||
font-weight:bold;
|
||||
letter-spacing: 0.1rem;
|
||||
padding: 1rem 0 0 0 !important;
|
||||
color: #ffffff;
|
||||
padding: 1rem 1.5rem;
|
||||
color: #32325d;
|
||||
border-radius: .375rem;
|
||||
background: #fff;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,.03);
|
||||
}
|
||||
|
||||
#cbi-dropbear h2,
|
||||
@@ -2304,8 +2308,7 @@ form.inline+form.inline,
|
||||
.cbi-value-field .cbi-button-add,
|
||||
.cbi-value-field .cbi-button-remove,
|
||||
.cbi-value-field .cbi-button-neutral {
|
||||
height: 2.5rem;
|
||||
line-height: 2.5rem;
|
||||
|
||||
min-width: 2.5rem !important;
|
||||
}
|
||||
|
||||
@@ -2317,6 +2320,7 @@ form.inline+form.inline,
|
||||
padding-left: 1rem;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 0.375rem;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,.03);
|
||||
}
|
||||
|
||||
.cbi-tabmenu>li,
|
||||
@@ -2626,7 +2630,7 @@ select[multiple="multiple"] {
|
||||
box-shadow: 0 0 0rem 0 rgba(136, 152, 170, .15);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding: 0.5rem 0;
|
||||
padding: 0rem 0;
|
||||
}
|
||||
|
||||
#cbi-network-lan.cbi-section-node {
|
||||
@@ -2649,11 +2653,11 @@ select[multiple="multiple"] {
|
||||
.cbi-value-field,
|
||||
.cbi-value-description {
|
||||
display: table-cell;
|
||||
line-height: 1.25;
|
||||
line-height: 1.6;
|
||||
font-size: 0.875rem;
|
||||
|
||||
}
|
||||
|
||||
div.cbi-value-field {}
|
||||
|
||||
|
||||
.cbi-value-helpicon>img {
|
||||
@@ -2717,8 +2721,8 @@ div.cbi-value-field {}
|
||||
}
|
||||
|
||||
.cbi-map-descr {
|
||||
margin: 0rem 0 1rem 0rem;
|
||||
color: #fff;
|
||||
margin: 0rem 0 1rem 1.5rem;
|
||||
color: #32325d;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
@@ -3486,11 +3490,27 @@ header>.container>.pull-right>* {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.node-network-diagnostics .cbi-section div{
|
||||
padding:0 1.5rem;
|
||||
}
|
||||
|
||||
.node-network-diagnostics #diag-rc-output pre{
|
||||
padding:1rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* fix nlbw/display*/
|
||||
#detail-bubble.in{
|
||||
z-index: 500;
|
||||
}
|
||||
|
||||
.node-nlbw-display .cbi-section ul{
|
||||
padding:0.875rem 1.5rem;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1600px) {
|
||||
.main-left {
|
||||
@@ -3924,6 +3944,10 @@ header>.container>.pull-right>* {
|
||||
|
||||
h2 {
|
||||
color: #ccc;
|
||||
background: #333333;
|
||||
}
|
||||
.cbi-map-descr {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.cbi-section {
|
||||
@@ -4222,6 +4246,12 @@ header>.container>.pull-right>* {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
#detail-bubble > div {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
padding: 5px;
|
||||
background: #252525;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 156 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 388 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 166 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 156 KiB |
@@ -10,7 +10,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=rclone-ng
|
||||
PKG_VERSION:=0.3.2
|
||||
PKG_VERSION:=0.4.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_LICENSE:=GPLv3
|
||||
@@ -21,7 +21,7 @@ include $(INCLUDE_DIR)/package.mk
|
||||
PKG_SOURCE:=RcloneNg-v$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/ElonH/RcloneNg/releases/download/v$(PKG_VERSION)/
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_HASH:=441fdfa577bdda7f58f62f6e75174a4a48e44d7c1361f7123d9699d791c08b5a
|
||||
PKG_HASH:=d974d5476b89281dcc14b0081e26f286041dd799898bc6b163d349d504056bd1
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=net
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=rclone
|
||||
PKG_VERSION:=1.52.1
|
||||
PKG_VERSION:=1.52.2
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/rclone/rclone.git
|
||||
PKG_SOURCE_DATE:=2020-06-10
|
||||
PKG_SOURCE_VERSION:=31dc78905ea8dfb22c43724527b19e097e05c26a
|
||||
PKG_SOURCE_DATE:=2020-06-24
|
||||
PKG_SOURCE_VERSION:=d8144a7e84dc3fb4975adf1bce707a5be672fada
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_MIRROR_HASH:=fa79f62babc2f42691c9ad83ef906e90061d4ca6adcc97150c2906605312db66
|
||||
PKG_MIRROR_HASH:=8a6f3fd465e57f5f3b9cfe3958eeb020f72b4940bfbf4993b9580659041c3735
|
||||
|
||||
PKG_LICENSE:=GPLv3
|
||||
PKG_MAINTAINER:=ElonH <elonhhuang@gmail.com>
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=kcptun
|
||||
PKG_VERSION:=20200409
|
||||
PKG_VERSION:=20200701
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/xtaci/kcptun/tar.gz/v$(PKG_VERSION)?
|
||||
PKG_HASH:=312b8f438549225dfd1eac95444dd6a4c50610578ddcf7ff21e19c73a855d4bc
|
||||
PKG_HASH:=d5b2d212c6806f1c4eba5fbce8797734eaa8ae0f8cdd90dd06d0844392888ff0
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_LICENSE_FILES:=LICENSE.md
|
||||
|
||||
@@ -8,26 +8,25 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=json-c
|
||||
PKG_VERSION:=0.13.1
|
||||
PKG_RELEASE:=2
|
||||
PKG_VERSION:=0.14
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-nodoc.tar.gz
|
||||
PKG_SOURCE_URL:=https://s3.amazonaws.com/json-c_releases/releases/
|
||||
PKG_HASH:=94a26340c0785fcff4f46ff38609cf84ebcd670df0c8efd75d039cc951d80132
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
|
||||
PKG_HASH:=99914e644a25201d82ccefa20430f7515c110923360f9ef46755527c02412afa
|
||||
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_LICENSE_FILES:=COPYING
|
||||
PKG_CPE_ID:=cpe:/a:json-c_project:json-c
|
||||
|
||||
PKG_FIXUP:=autoreconf
|
||||
PKG_INSTALL:=1
|
||||
CMAKE_INSTALL:=1
|
||||
CMAKE_OPTIONS += -DCMAKE_INSTALL_INCLUDEDIR=$(STAGING_DIR)/usr/include
|
||||
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
TARGET_CFLAGS += $(FPIC) -Wno-implicit-fallthrough
|
||||
HOST_CFLAGS += -Wno-implicit-fallthrough
|
||||
@@ -38,22 +37,13 @@ define Package/libjson-c
|
||||
CATEGORY:=Libraries
|
||||
TITLE:=javascript object notation
|
||||
URL:=https://json-c.github.io/json-c/
|
||||
ABI_VERSION:=4
|
||||
ABI_VERSION:=5
|
||||
endef
|
||||
|
||||
define Package/libjson-c/description
|
||||
This package contains a library for javascript object notation backends.
|
||||
endef
|
||||
|
||||
define Build/InstallDev
|
||||
$(INSTALL_DIR) $(1)/usr/include
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/include/json-c $(1)/usr/include/
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libjson-c.{a,so*} $(1)/usr/lib/
|
||||
$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/json-c.pc $(1)/usr/lib/pkgconfig/
|
||||
endef
|
||||
|
||||
define Package/libjson-c/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libjson-c.so.* $(1)/usr/lib/
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -76,12 +76,6 @@ AC_FUNC_VPRINTF
|
||||
AC_FUNC_MEMCMP
|
||||
AC_CHECK_FUNCS([realloc])
|
||||
AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale)
|
||||
-AC_CHECK_DECLS([INFINITY], [], [], [[#include <math.h>]])
|
||||
-AC_CHECK_DECLS([nan], [], [], [[#include <math.h>]])
|
||||
-AC_CHECK_DECLS([isnan], [], [], [[#include <math.h>]])
|
||||
-AC_CHECK_DECLS([isinf], [], [], [[#include <math.h>]])
|
||||
-AC_CHECK_DECLS([_isnan], [], [], [[#include <float.h>]])
|
||||
-AC_CHECK_DECLS([_finite], [], [], [[#include <float.h>]])
|
||||
AC_MSG_CHECKING(for GCC atomic builtins)
|
||||
AC_LINK_IFELSE(
|
||||
[
|
||||
--- a/math_compat.h
|
||||
+++ b/math_compat.h
|
||||
@@ -6,31 +6,9 @@
|
||||
@@ -22,17 +7,17 @@
|
||||
-/* Define isnan, isinf, infinity and nan on Windows/MSVC */
|
||||
-
|
||||
-#ifndef HAVE_DECL_ISNAN
|
||||
-# ifdef HAVE_DECL__ISNAN
|
||||
-#ifdef HAVE_DECL__ISNAN
|
||||
-#include <float.h>
|
||||
-#define isnan(x) _isnan(x)
|
||||
-# endif
|
||||
-#endif
|
||||
-#endif
|
||||
-
|
||||
-#ifndef HAVE_DECL_ISINF
|
||||
-# ifdef HAVE_DECL__FINITE
|
||||
-#ifdef HAVE_DECL__FINITE
|
||||
-#include <float.h>
|
||||
-#define isinf(x) (!_finite(x))
|
||||
-# endif
|
||||
-#endif
|
||||
-#endif
|
||||
-
|
||||
-#ifndef HAVE_DECL_INFINITY
|
||||
|
||||
180
package/libs/libjson-c/patches/001-Fix-CVE-2020-12762.patch
Normal file
180
package/libs/libjson-c/patches/001-Fix-CVE-2020-12762.patch
Normal file
File diff suppressed because one or more lines are too long
@@ -1,27 +0,0 @@
|
||||
From 099016b7e8d70a6d5dd814e788bba08d33d48426 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Stoeckmann <tobias@stoeckmann.org>
|
||||
Date: Mon, 4 May 2020 19:41:16 +0200
|
||||
Subject: [PATCH 1/2] Protect array_list_del_idx against size_t overflow.
|
||||
|
||||
If the assignment of stop overflows due to idx and count being
|
||||
larger than SIZE_T_MAX in sum, out of boundary access could happen.
|
||||
|
||||
It takes invalid usage of this function for this to happen, but
|
||||
I decided to add this check so array_list_del_idx is as safe against
|
||||
bad usage as the other arraylist functions.
|
||||
---
|
||||
arraylist.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/arraylist.c
|
||||
+++ b/arraylist.c
|
||||
@@ -135,6 +135,9 @@ array_list_del_idx( struct array_list *a
|
||||
{
|
||||
size_t i, stop;
|
||||
|
||||
+ /* Avoid overflow in calculation with large indices. */
|
||||
+ if (idx > SIZE_T_MAX - count)
|
||||
+ return -1;
|
||||
stop = idx + count;
|
||||
if ( idx >= arr->length || stop > arr->length ) return -1;
|
||||
for ( i = idx; i < stop; ++i ) {
|
||||
@@ -1,32 +0,0 @@
|
||||
From 77d935b7ae7871a1940cd827e850e6063044ec45 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Stoeckmann <tobias@stoeckmann.org>
|
||||
Date: Mon, 4 May 2020 19:46:45 +0200
|
||||
Subject: [PATCH 2/2] Prevent division by zero in linkhash.
|
||||
|
||||
If a linkhash with a size of zero is created, then modulo operations
|
||||
are prone to division by zero operations.
|
||||
|
||||
Purely protective measure against bad usage.
|
||||
---
|
||||
linkhash.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/linkhash.c
|
||||
+++ b/linkhash.c
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
+#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -498,6 +499,8 @@ struct lh_table* lh_table_new(int size,
|
||||
int i;
|
||||
struct lh_table *t;
|
||||
|
||||
+ /* Allocate space for elements to avoid divisions by zero. */
|
||||
+ assert(size > 0);
|
||||
t = (struct lh_table*)calloc(1, sizeof(struct lh_table));
|
||||
if (!t)
|
||||
return NULL;
|
||||
@@ -1,86 +0,0 @@
|
||||
From d07b91014986900a3a75f306d302e13e005e9d67 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Stoeckmann <tobias@stoeckmann.org>
|
||||
Date: Mon, 4 May 2020 19:47:25 +0200
|
||||
Subject: [PATCH] Fix integer overflows.
|
||||
|
||||
The data structures linkhash and printbuf are limited to 2 GB in size
|
||||
due to a signed integer being used to track their current size.
|
||||
|
||||
If too much data is added, then size variable can overflow, which is
|
||||
an undefined behaviour in C programming language.
|
||||
|
||||
Assuming that a signed int overflow just leads to a negative value,
|
||||
like it happens on many sytems (Linux i686/amd64 with gcc), then
|
||||
printbuf is vulnerable to an out of boundary write on 64 bit systems.
|
||||
---
|
||||
linkhash.c | 7 +++++--
|
||||
printbuf.c | 19 ++++++++++++++++---
|
||||
2 files changed, 21 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/linkhash.c
|
||||
+++ b/linkhash.c
|
||||
@@ -579,9 +579,12 @@ int lh_table_insert_w_hash(struct lh_tab
|
||||
{
|
||||
unsigned long n;
|
||||
|
||||
- if (t->count >= t->size * LH_LOAD_FACTOR)
|
||||
- if (lh_table_resize(t, t->size * 2) != 0)
|
||||
+ if (t->count >= t->size * LH_LOAD_FACTOR) {
|
||||
+ /* Avoid signed integer overflow with large tables. */
|
||||
+ int new_size = INT_MAX / 2 < t->size ? t->size * 2 : INT_MAX;
|
||||
+ if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0)
|
||||
return -1;
|
||||
+ }
|
||||
|
||||
n = h % t->size;
|
||||
|
||||
--- a/printbuf.c
|
||||
+++ b/printbuf.c
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
+#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -65,9 +66,16 @@ static int printbuf_extend(struct printb
|
||||
if (p->size >= min_size)
|
||||
return 0;
|
||||
|
||||
- new_size = p->size * 2;
|
||||
- if (new_size < min_size + 8)
|
||||
- new_size = min_size + 8;
|
||||
+ /* Prevent signed integer overflows with large buffers. */
|
||||
+ if (min_size > INT_MAX - 8)
|
||||
+ return -1;
|
||||
+ if (p->size > INT_MAX / 2)
|
||||
+ new_size = min_size + 8;
|
||||
+ else {
|
||||
+ new_size = p->size * 2;
|
||||
+ if (new_size < min_size + 8)
|
||||
+ new_size = min_size + 8;
|
||||
+ }
|
||||
#ifdef PRINTBUF_DEBUG
|
||||
MC_DEBUG("printbuf_memappend: realloc "
|
||||
"bpos=%d min_size=%d old_size=%d new_size=%d\n",
|
||||
@@ -82,6 +90,9 @@ static int printbuf_extend(struct printb
|
||||
|
||||
int printbuf_memappend(struct printbuf *p, const char *buf, int size)
|
||||
{
|
||||
+ /* Prevent signed integer overflows with large buffers. */
|
||||
+ if (size > INT_MAX - p->bpos - 1)
|
||||
+ return -1;
|
||||
if (p->size <= p->bpos + size + 1) {
|
||||
if (printbuf_extend(p, p->bpos + size + 1) < 0)
|
||||
return -1;
|
||||
@@ -98,6 +109,9 @@ int printbuf_memset(struct printbuf *pb,
|
||||
|
||||
if (offset == -1)
|
||||
offset = pb->bpos;
|
||||
+ /* Prevent signed integer overflows with large buffers. */
|
||||
+ if (len > INT_MAX - offset)
|
||||
+ return -1;
|
||||
size_needed = offset + len;
|
||||
if (pb->size < size_needed)
|
||||
{
|
||||
@@ -1,29 +0,0 @@
|
||||
From 519dfe1591d85432986f9762d41d1a883198c157 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Haszlakiewicz <erh+git@nimenees.com>
|
||||
Date: Sun, 10 May 2020 03:32:19 +0000
|
||||
Subject: [PATCH] Issue #599: Fix the backwards check in
|
||||
lh_table_insert_w_hash() that was preventing adding more than 11 objects. Add
|
||||
a test to check for this too.
|
||||
|
||||
---
|
||||
linkhash.c | 2 +-
|
||||
tests/test4.c | 29 +++++++++++++++++++++++++++++
|
||||
tests/test4.expected | 1 +
|
||||
3 files changed, 31 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/linkhash.c b/linkhash.c
|
||||
index 51e90b1..f930efd 100644
|
||||
--- a/linkhash.c
|
||||
+++ b/linkhash.c
|
||||
@@ -582,7 +582,7 @@ int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, con
|
||||
|
||||
if (t->count >= t->size * LH_LOAD_FACTOR) {
|
||||
/* Avoid signed integer overflow with large tables. */
|
||||
- int new_size = INT_MAX / 2 < t->size ? t->size * 2 : INT_MAX;
|
||||
+ int new_size = (t->size > INT_MAX / 2) ? INT_MAX : (t->size * 2);
|
||||
if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0)
|
||||
return -1;
|
||||
}
|
||||
--
|
||||
2.26.2
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=libubox
|
||||
PKG_RELEASE=5
|
||||
PKG_RELEASE=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/libubox.git
|
||||
PKG_SOURCE_DATE:=2018-07-25
|
||||
PKG_SOURCE_VERSION:=c83a84afbef2b24f960ddeda0b5e2ab01fba6981
|
||||
PKG_MIRROR_HASH:=4a9594d2ae3706174d182a21fe815f1d18c20beca6593707cc757994975dc670
|
||||
PKG_MIRROR_HASH:=3d58def8e415ceda8aacfd8453813d8bf2a05991c0df0c074744639ab04321ba
|
||||
PKG_SOURCE_DATE:=2020-05-25
|
||||
PKG_SOURCE_VERSION:=66195aee50424cbda0c2d858014e4cc58a2dc029
|
||||
CMAKE_INSTALL:=1
|
||||
|
||||
PKG_LICENSE:=ISC
|
||||
@@ -27,7 +27,7 @@ define Package/libubox
|
||||
SECTION:=libs
|
||||
CATEGORY:=Libraries
|
||||
TITLE:=Basic utility library
|
||||
ABI_VERSION:=20180725
|
||||
ABI_VERSION:=20191228
|
||||
DEPENDS:=
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From 2acfe84e4c871fb994c38c9f2508eb9ebd296b74 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Tue, 19 Nov 2019 17:34:25 +0100
|
||||
Subject: blobmsg_json: fix possible uninitialized struct member
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
clang-10 analyzer reports following:
|
||||
|
||||
blobmsg_json.c:285:2: warning: The expression is an uninitialized value. The computed value will also be garbage
|
||||
s->indent_level++;
|
||||
^~~~~~~~~~~~~~~~~
|
||||
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg_json.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/blobmsg_json.c
|
||||
+++ b/blobmsg_json.c
|
||||
@@ -316,7 +316,7 @@ static void setup_strbuf(struct strbuf *
|
||||
|
||||
char *blobmsg_format_json_with_cb(struct blob_attr *attr, bool list, blobmsg_json_format_t cb, void *priv, int indent)
|
||||
{
|
||||
- struct strbuf s;
|
||||
+ struct strbuf s = {0};
|
||||
bool array;
|
||||
char *ret;
|
||||
|
||||
@@ -350,7 +350,7 @@ char *blobmsg_format_json_with_cb(struct
|
||||
|
||||
char *blobmsg_format_json_value_with_cb(struct blob_attr *attr, blobmsg_json_format_t cb, void *priv, int indent)
|
||||
{
|
||||
- struct strbuf s;
|
||||
+ struct strbuf s = {0};
|
||||
char *ret;
|
||||
|
||||
setup_strbuf(&s, attr, cb, priv, indent);
|
||||
@@ -1,39 +0,0 @@
|
||||
From f27853d71a2cb99ec5de3881716a14611ada307c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Sat, 23 Nov 2019 22:48:25 +0100
|
||||
Subject: jshn: fix off by one in jshn_parse_file
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fixes following error:
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x4C32D04: strlen
|
||||
by 0x5043367: json_tokener_parse_ex
|
||||
by 0x5045316: json_tokener_parse_verbose
|
||||
by 0x504537D: json_tokener_parse
|
||||
by 0x401AB1: jshn_parse (jshn.c:179)
|
||||
by 0x40190D: jshn_parse_file (jshn.c:370)
|
||||
by 0x40190D: main (jshn.c:434)
|
||||
Address 0x5848c4c is 0 bytes after a block of size 1,036 alloc'd
|
||||
at 0x4C2FB0F: malloc
|
||||
by 0x4018E2: jshn_parse_file (jshn.c:357)
|
||||
by 0x4018E2: main (jshn.c:434)
|
||||
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
jshn.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/jshn.c
|
||||
+++ b/jshn.c
|
||||
@@ -384,7 +384,7 @@ int main(int argc, char **argv)
|
||||
close(fd);
|
||||
return 3;
|
||||
}
|
||||
- if (!(fbuf = malloc(sb.st_size))) {
|
||||
+ if (!(fbuf = calloc(1, sb.st_size+1))) {
|
||||
fprintf(stderr, "Error allocating memory for %s\n", optarg);
|
||||
close(fd);
|
||||
return 3;
|
||||
@@ -1,97 +0,0 @@
|
||||
From af2a074160e32692b570f8a3562b4370d38f34e7 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Mon, 9 Dec 2019 13:53:27 +0100
|
||||
Subject: blob: refactor attr parsing into separate function
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Making blob_parse easier to review.
|
||||
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blob.c | 61 +++++++++++++++++++++++++++++++++-------------------------
|
||||
1 file changed, 35 insertions(+), 26 deletions(-)
|
||||
|
||||
--- a/blob.c
|
||||
+++ b/blob.c
|
||||
@@ -217,44 +217,53 @@ blob_check_type(const void *ptr, unsigne
|
||||
return true;
|
||||
}
|
||||
|
||||
-int
|
||||
-blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||
+static int
|
||||
+blob_parse_attr(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||
{
|
||||
- struct blob_attr *pos;
|
||||
int found = 0;
|
||||
- int rem;
|
||||
+ int id = blob_id(attr);
|
||||
+ size_t len = blob_len(attr);
|
||||
|
||||
- memset(data, 0, sizeof(struct blob_attr *) * max);
|
||||
- blob_for_each_attr(pos, attr, rem) {
|
||||
- int id = blob_id(pos);
|
||||
- int len = blob_len(pos);
|
||||
+ if (id >= max)
|
||||
+ return 0;
|
||||
|
||||
- if (id >= max)
|
||||
- continue;
|
||||
+ if (info) {
|
||||
+ int type = info[id].type;
|
||||
|
||||
- if (info) {
|
||||
- int type = info[id].type;
|
||||
+ if (type < BLOB_ATTR_LAST) {
|
||||
+ if (!blob_check_type(blob_data(attr), len, type))
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
- if (type < BLOB_ATTR_LAST) {
|
||||
- if (!blob_check_type(blob_data(pos), len, type))
|
||||
- continue;
|
||||
- }
|
||||
+ if (info[id].minlen && len < info[id].minlen)
|
||||
+ return 0;
|
||||
|
||||
- if (info[id].minlen && len < info[id].minlen)
|
||||
- continue;
|
||||
+ if (info[id].maxlen && len > info[id].maxlen)
|
||||
+ return 0;
|
||||
|
||||
- if (info[id].maxlen && len > info[id].maxlen)
|
||||
- continue;
|
||||
+ if (info[id].validate && !info[id].validate(&info[id], attr))
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
- if (info[id].validate && !info[id].validate(&info[id], pos))
|
||||
- continue;
|
||||
- }
|
||||
+ if (!data[id])
|
||||
+ found++;
|
||||
|
||||
- if (!data[id])
|
||||
- found++;
|
||||
+ data[id] = attr;
|
||||
+ return found;
|
||||
+}
|
||||
|
||||
- data[id] = pos;
|
||||
+int
|
||||
+blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||
+{
|
||||
+ struct blob_attr *pos;
|
||||
+ int found = 0;
|
||||
+ size_t rem;
|
||||
+
|
||||
+ memset(data, 0, sizeof(struct blob_attr *) * max);
|
||||
+ blob_for_each_attr(pos, attr, rem) {
|
||||
+ found += blob_parse_attr(pos, data, info, max);
|
||||
}
|
||||
+
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
From b6a0a070f2e14808e835c2fcfa3820a55041902f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Mon, 9 Dec 2019 14:11:45 +0100
|
||||
Subject: blob: introduce blob_parse_untrusted
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
blob_parse can be only used on trusted input as it has no possibility to
|
||||
check the length of the provided input buffer, which might lead to
|
||||
undefined behaviour and/or crashes when supplied with malformed,
|
||||
corrupted or otherwise specially crafted input.
|
||||
|
||||
So this introduces blob_parse_untrusted variant which expects additional
|
||||
input buffer length argument and thus should be able to process also
|
||||
inputs from untrusted sources.
|
||||
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blob.c | 24 ++++++++++++++++++++++++
|
||||
blob.h | 7 +++++++
|
||||
2 files changed, 31 insertions(+)
|
||||
|
||||
--- a/blob.c
|
||||
+++ b/blob.c
|
||||
@@ -253,6 +253,30 @@ blob_parse_attr(struct blob_attr *attr,
|
||||
}
|
||||
|
||||
int
|
||||
+blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||
+{
|
||||
+ struct blob_attr *pos;
|
||||
+ size_t len = 0;
|
||||
+ int found = 0;
|
||||
+ size_t rem;
|
||||
+
|
||||
+ if (!attr || attr_len < sizeof(struct blob_attr))
|
||||
+ return 0;
|
||||
+
|
||||
+ len = blob_raw_len(attr);
|
||||
+ if (len != attr_len)
|
||||
+ return 0;
|
||||
+
|
||||
+ memset(data, 0, sizeof(struct blob_attr *) * max);
|
||||
+ blob_for_each_attr_len(pos, attr, len, rem) {
|
||||
+ found += blob_parse_attr(pos, rem, data, info, max);
|
||||
+ }
|
||||
+
|
||||
+ return found;
|
||||
+}
|
||||
+
|
||||
+/* use only on trusted input, otherwise consider blob_parse_untrusted */
|
||||
+int
|
||||
blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||
{
|
||||
struct blob_attr *pos;
|
||||
--- a/blob.h
|
||||
+++ b/blob.h
|
||||
@@ -199,6 +199,7 @@ extern void blob_nest_end(struct blob_bu
|
||||
extern struct blob_attr *blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len);
|
||||
extern bool blob_check_type(const void *ptr, unsigned int len, int type);
|
||||
extern int blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max);
|
||||
+extern int blob_parse_untrusted(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max);
|
||||
extern struct blob_attr *blob_memdup(struct blob_attr *attr);
|
||||
extern struct blob_attr *blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len);
|
||||
|
||||
@@ -254,5 +255,11 @@ blob_put_u64(struct blob_buf *buf, int i
|
||||
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||
rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||
|
||||
+#define blob_for_each_attr_len(pos, attr, attr_len, rem) \
|
||||
+ for (rem = attr ? blob_len(attr) : 0, \
|
||||
+ pos = (struct blob_attr *) (attr ? blob_data(attr) : NULL); \
|
||||
+ rem >= sizeof(struct blob_attr) && rem < attr_len && (blob_pad_len(pos) <= rem) && \
|
||||
+ (blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||
+ rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
From 7425d421340594f50c717ff7129b6ee71280a447 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Mon, 9 Dec 2019 15:27:16 +0100
|
||||
Subject: blob: fix OOB access in blob_check_type
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Found by fuzzer:
|
||||
|
||||
ERROR: AddressSanitizer: SEGV on unknown address 0x602100000455
|
||||
The signal is caused by a READ memory access.
|
||||
#0 in blob_check_type blob.c:214:43
|
||||
#1 in blob_parse_attr blob.c:234:9
|
||||
#2 in blob_parse_untrusted blob.c:272:12
|
||||
#3 in fuzz_blob_parse tests/fuzzer/test-blob-parse-fuzzer.c:34:2
|
||||
#4 in LLVMFuzzerTestOneInput tests/fuzzer/test-blob-parse-fuzzer.c:39:2
|
||||
|
||||
Caused by following line:
|
||||
|
||||
if (type == BLOB_ATTR_STRING && data[len - 1] != 0)
|
||||
|
||||
where len was pointing outside of the data buffer.
|
||||
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blob.c | 23 ++++++++++++++++++-----
|
||||
1 file changed, 18 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/blob.c
|
||||
+++ b/blob.c
|
||||
@@ -218,20 +218,33 @@ blob_check_type(const void *ptr, unsigne
|
||||
}
|
||||
|
||||
static int
|
||||
-blob_parse_attr(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||
+blob_parse_attr(struct blob_attr *attr, size_t attr_len, struct blob_attr **data, const struct blob_attr_info *info, int max)
|
||||
{
|
||||
+ int id;
|
||||
+ size_t len;
|
||||
int found = 0;
|
||||
- int id = blob_id(attr);
|
||||
- size_t len = blob_len(attr);
|
||||
+ size_t data_len;
|
||||
|
||||
+ if (!attr || attr_len < sizeof(struct blob_attr))
|
||||
+ return 0;
|
||||
+
|
||||
+ id = blob_id(attr);
|
||||
if (id >= max)
|
||||
return 0;
|
||||
|
||||
+ len = blob_raw_len(attr);
|
||||
+ if (len > attr_len || len < sizeof(struct blob_attr))
|
||||
+ return 0;
|
||||
+
|
||||
+ data_len = blob_len(attr);
|
||||
+ if (data_len > len)
|
||||
+ return 0;
|
||||
+
|
||||
if (info) {
|
||||
int type = info[id].type;
|
||||
|
||||
if (type < BLOB_ATTR_LAST) {
|
||||
- if (!blob_check_type(blob_data(attr), len, type))
|
||||
+ if (!blob_check_type(blob_data(attr), data_len, type))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -285,7 +298,7 @@ blob_parse(struct blob_attr *attr, struc
|
||||
|
||||
memset(data, 0, sizeof(struct blob_attr *) * max);
|
||||
blob_for_each_attr(pos, attr, rem) {
|
||||
- found += blob_parse_attr(pos, data, info, max);
|
||||
+ found += blob_parse_attr(pos, rem, data, info, max);
|
||||
}
|
||||
|
||||
return found;
|
||||
@@ -1,32 +0,0 @@
|
||||
From 0773eef13674964d890420673d2501342979d8bf Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Tue, 10 Dec 2019 12:02:40 +0100
|
||||
Subject: blobmsg: fix heap buffer overflow in blobmsg_parse
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fixes following error found by the fuzzer:
|
||||
|
||||
==29774==ERROR: AddressSanitizer: heap-buffer-overflow
|
||||
READ of size 1 at 0x6020004f1c56 thread T0
|
||||
#0 strcmp sanitizer_common_interceptors.inc:442:3
|
||||
#1 blobmsg_parse blobmsg.c:168:8
|
||||
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -52,6 +52,9 @@ bool blobmsg_check_attr(const struct blo
|
||||
|
||||
id = blob_id(attr);
|
||||
len = blobmsg_data_len(attr);
|
||||
+ if (len > blob_raw_len(attr))
|
||||
+ return false;
|
||||
+
|
||||
data = blobmsg_data(attr);
|
||||
|
||||
if (id > BLOBMSG_TYPE_LAST)
|
||||
@@ -1,51 +0,0 @@
|
||||
From cec3ed2550073abbfe0f1f6131c44f90c9d05aa8 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Schramm <tobleminer@gmail.com>
|
||||
Date: Wed, 28 Nov 2018 13:39:29 +0100
|
||||
Subject: Ensure blob_attr length check does not perform out of bounds reads
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Before there might have been as little as one single byte left which
|
||||
would result in 3 bytes of blob_attr->id_len being out of bounds.
|
||||
|
||||
Acked-by: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
Signed-off-by: Tobias Schramm <tobleminer@gmail.com>
|
||||
[line wrapped < 72 chars]
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blob.h | 4 ++--
|
||||
blobmsg.h | 2 +-
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/blob.h
|
||||
+++ b/blob.h
|
||||
@@ -243,7 +243,7 @@ blob_put_u64(struct blob_buf *buf, int i
|
||||
|
||||
#define __blob_for_each_attr(pos, attr, rem) \
|
||||
for (pos = (struct blob_attr *) attr; \
|
||||
- rem > 0 && (blob_pad_len(pos) <= rem) && \
|
||||
+ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \
|
||||
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||
rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||
|
||||
@@ -251,7 +251,7 @@ blob_put_u64(struct blob_buf *buf, int i
|
||||
#define blob_for_each_attr(pos, attr, rem) \
|
||||
for (rem = attr ? blob_len(attr) : 0, \
|
||||
pos = (struct blob_attr *) (attr ? blob_data(attr) : NULL); \
|
||||
- rem > 0 && (blob_pad_len(pos) <= rem) && \
|
||||
+ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \
|
||||
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||
rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||
|
||||
--- a/blobmsg.h
|
||||
+++ b/blobmsg.h
|
||||
@@ -266,7 +266,7 @@ int blobmsg_printf(struct blob_buf *buf,
|
||||
#define blobmsg_for_each_attr(pos, attr, rem) \
|
||||
for (rem = attr ? blobmsg_data_len(attr) : 0, \
|
||||
pos = (struct blob_attr *) (attr ? blobmsg_data(attr) : NULL); \
|
||||
- rem > 0 && (blob_pad_len(pos) <= rem) && \
|
||||
+ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \
|
||||
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||
rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
From 8b6a401638317906b6d9039417c1c19ea8cfeab0 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Schramm <tobleminer@gmail.com>
|
||||
Date: Tue, 13 Nov 2018 04:16:12 +0100
|
||||
Subject: Replace use of blobmsg_check_attr by blobmsg_check_attr_len
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
blobmsg_check_attr_len adds a length limit specifying the max offset
|
||||
from attr that can be read safely.
|
||||
|
||||
Signed-off-by: Tobias Schramm <tobleminer@gmail.com>
|
||||
[rebased and reworked, line wrapped commit message, _safe -> _len]
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg.c | 59 +++++++++++++++++++++++++++++++++++++++++++------------
|
||||
blobmsg.h | 2 ++
|
||||
2 files changed, 48 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -33,37 +33,70 @@ blobmsg_namelen(const struct blobmsg_hdr
|
||||
|
||||
bool blobmsg_check_attr(const struct blob_attr *attr, bool name)
|
||||
{
|
||||
+ return blobmsg_check_attr_len(attr, name, blob_raw_len(attr));
|
||||
+}
|
||||
+
|
||||
+static bool blobmsg_check_name(const struct blob_attr *attr, size_t len, bool name)
|
||||
+{
|
||||
+ char *limit = (char *) attr + len;
|
||||
const struct blobmsg_hdr *hdr;
|
||||
- const char *data;
|
||||
- int id, len;
|
||||
|
||||
- if (blob_len(attr) < sizeof(struct blobmsg_hdr))
|
||||
+ hdr = blob_data(attr);
|
||||
+ if (name && !hdr->namelen)
|
||||
return false;
|
||||
|
||||
- hdr = (void *) attr->data;
|
||||
- if (!hdr->namelen && name)
|
||||
+ if ((char *) hdr->name + blobmsg_namelen(hdr) > limit)
|
||||
return false;
|
||||
|
||||
- if (blobmsg_namelen(hdr) > blob_len(attr) - sizeof(struct blobmsg_hdr))
|
||||
+ if (blobmsg_namelen(hdr) > (blob_len(attr) - sizeof(struct blobmsg_hdr)))
|
||||
return false;
|
||||
|
||||
if (hdr->name[blobmsg_namelen(hdr)] != 0)
|
||||
return false;
|
||||
|
||||
- id = blob_id(attr);
|
||||
- len = blobmsg_data_len(attr);
|
||||
- if (len > blob_raw_len(attr))
|
||||
- return false;
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static const char* blobmsg_check_data(const struct blob_attr *attr, size_t len, size_t *data_len)
|
||||
+{
|
||||
+ char *limit = (char *) attr + len;
|
||||
+ const char *data;
|
||||
+
|
||||
+ *data_len = blobmsg_data_len(attr);
|
||||
+ if (*data_len > blob_raw_len(attr))
|
||||
+ return NULL;
|
||||
|
||||
data = blobmsg_data(attr);
|
||||
+ if (data + *data_len > limit)
|
||||
+ return NULL;
|
||||
|
||||
+ return data;
|
||||
+}
|
||||
+
|
||||
+bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len)
|
||||
+{
|
||||
+ const char *data;
|
||||
+ size_t data_len;
|
||||
+ int id;
|
||||
+
|
||||
+ if (len < sizeof(struct blob_attr))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!blobmsg_check_name(attr, len, name))
|
||||
+ return false;
|
||||
+
|
||||
+ id = blob_id(attr);
|
||||
if (id > BLOBMSG_TYPE_LAST)
|
||||
return false;
|
||||
|
||||
if (!blob_type[id])
|
||||
return true;
|
||||
|
||||
- return blob_check_type(data, len, blob_type[id]);
|
||||
+ data = blobmsg_check_data(attr, len, &data_len);
|
||||
+ if (!data)
|
||||
+ return false;
|
||||
+
|
||||
+ return blob_check_type(data, data_len, blob_type[id]);
|
||||
}
|
||||
|
||||
int blobmsg_check_array(const struct blob_attr *attr, int type)
|
||||
@@ -114,7 +147,7 @@ int blobmsg_parse_array(const struct blo
|
||||
blob_id(attr) != policy[i].type)
|
||||
continue;
|
||||
|
||||
- if (!blobmsg_check_attr(attr, false))
|
||||
+ if (!blobmsg_check_attr_len(attr, false, len))
|
||||
return -1;
|
||||
|
||||
if (tb[i])
|
||||
@@ -161,7 +194,7 @@ int blobmsg_parse(const struct blobmsg_p
|
||||
if (blobmsg_namelen(hdr) != pslen[i])
|
||||
continue;
|
||||
|
||||
- if (!blobmsg_check_attr(attr, true))
|
||||
+ if (!blobmsg_check_attr_len(attr, true, len))
|
||||
return -1;
|
||||
|
||||
if (tb[i])
|
||||
--- a/blobmsg.h
|
||||
+++ b/blobmsg.h
|
||||
@@ -107,6 +107,8 @@ static inline int blobmsg_len(const stru
|
||||
bool blobmsg_check_attr(const struct blob_attr *attr, bool name);
|
||||
bool blobmsg_check_attr_list(const struct blob_attr *attr, int type);
|
||||
|
||||
+bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len);
|
||||
+
|
||||
/*
|
||||
* blobmsg_check_array: validate array/table and return size
|
||||
*
|
||||
@@ -1,157 +0,0 @@
|
||||
From ad29d0304983e283d4aec4ee5462942eaf5c03ac Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Schramm <tobleminer@gmail.com>
|
||||
Date: Thu, 15 Nov 2018 03:42:48 +0100
|
||||
Subject: blobmsg: add _len variants for all attribute checking methods
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Introduce _len variants of blobmsg attribute checking functions which
|
||||
aims to provide safer implementation as those functions should limit all
|
||||
memory accesses performed on the blob to the range [attr, attr + len]
|
||||
(upper bound non inclusive) and thus should be suited for checking of
|
||||
untrusted blob attributes.
|
||||
|
||||
While at it add some comments in order to make it clear.
|
||||
|
||||
Signed-off-by: Tobias Schramm <tobleminer@gmail.com>
|
||||
[_safe -> _len, blobmsg_check_array_len fix, commit subject/desc facelift]
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg.c | 21 ++++++++++++++++++---
|
||||
blobmsg.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 72 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -101,11 +101,21 @@ bool blobmsg_check_attr_len(const struct
|
||||
|
||||
int blobmsg_check_array(const struct blob_attr *attr, int type)
|
||||
{
|
||||
+ return blobmsg_check_array_len(attr, type, blob_raw_len(attr));
|
||||
+}
|
||||
+
|
||||
+int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len)
|
||||
+{
|
||||
struct blob_attr *cur;
|
||||
bool name;
|
||||
- int rem;
|
||||
int size = 0;
|
||||
|
||||
+ if (type > BLOBMSG_TYPE_LAST)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (!blobmsg_check_attr_len(attr, false, len))
|
||||
+ return -1;
|
||||
+
|
||||
switch (blobmsg_type(attr)) {
|
||||
case BLOBMSG_TYPE_TABLE:
|
||||
name = true;
|
||||
@@ -117,11 +127,11 @@ int blobmsg_check_array(const struct blo
|
||||
return -1;
|
||||
}
|
||||
|
||||
- blobmsg_for_each_attr(cur, attr, rem) {
|
||||
+ __blobmsg_for_each_attr(cur, attr, len) {
|
||||
if (type != BLOBMSG_TYPE_UNSPEC && blobmsg_type(cur) != type)
|
||||
return -1;
|
||||
|
||||
- if (!blobmsg_check_attr(cur, name))
|
||||
+ if (!blobmsg_check_attr_len(cur, name, len))
|
||||
return -1;
|
||||
|
||||
size++;
|
||||
@@ -135,6 +145,11 @@ bool blobmsg_check_attr_list(const struc
|
||||
return blobmsg_check_array(attr, type) >= 0;
|
||||
}
|
||||
|
||||
+bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len)
|
||||
+{
|
||||
+ return blobmsg_check_array_len(attr, type, len) >= 0;
|
||||
+}
|
||||
+
|
||||
int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
|
||||
struct blob_attr **tb, void *data, unsigned int len)
|
||||
{
|
||||
--- a/blobmsg.h
|
||||
+++ b/blobmsg.h
|
||||
@@ -104,19 +104,66 @@ static inline int blobmsg_len(const stru
|
||||
return blobmsg_data_len(attr);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * blobmsg_check_attr: validate a list of attributes
|
||||
+ *
|
||||
+ * This method may be used with trusted data only. Providing
|
||||
+ * malformed blobs will cause out of bounds memory access.
|
||||
+ */
|
||||
bool blobmsg_check_attr(const struct blob_attr *attr, bool name);
|
||||
-bool blobmsg_check_attr_list(const struct blob_attr *attr, int type);
|
||||
|
||||
+/*
|
||||
+ * blobmsg_check_attr_len: validate a list of attributes
|
||||
+ *
|
||||
+ * This method should be safer implementation of blobmsg_check_attr.
|
||||
+ * It will limit all memory access performed on the blob to the
|
||||
+ * range [attr, attr + len] (upper bound non inclusive) and is
|
||||
+ * thus suited for checking of untrusted blob attributes.
|
||||
+ */
|
||||
bool blobmsg_check_attr_len(const struct blob_attr *attr, bool name, size_t len);
|
||||
|
||||
/*
|
||||
+ * blobmsg_check_attr_list: validate a list of attributes
|
||||
+ *
|
||||
+ * This method may be used with trusted data only. Providing
|
||||
+ * malformed blobs will cause out of bounds memory access.
|
||||
+ */
|
||||
+bool blobmsg_check_attr_list(const struct blob_attr *attr, int type);
|
||||
+
|
||||
+/*
|
||||
+ * blobmsg_check_attr_list_len: validate a list of untrusted attributes
|
||||
+ *
|
||||
+ * This method should be safer implementation of blobmsg_check_attr_list.
|
||||
+ * It will limit all memory access performed on the blob to the
|
||||
+ * range [attr, attr + len] (upper bound non inclusive) and is
|
||||
+ * thus suited for checking of untrusted blob attributes.
|
||||
+ */
|
||||
+bool blobmsg_check_attr_list_len(const struct blob_attr *attr, int type, size_t len);
|
||||
+
|
||||
+/*
|
||||
* blobmsg_check_array: validate array/table and return size
|
||||
*
|
||||
* Checks if all elements of an array or table are valid and have
|
||||
* the specified type. Returns the number of elements in the array
|
||||
+ *
|
||||
+ * This method may be used with trusted data only. Providing
|
||||
+ * malformed blobs will cause out of bounds memory access.
|
||||
*/
|
||||
int blobmsg_check_array(const struct blob_attr *attr, int type);
|
||||
|
||||
+/*
|
||||
+ * blobmsg_check_array_len: validate untrusted array/table and return size
|
||||
+ *
|
||||
+ * Checks if all elements of an array or table are valid and have
|
||||
+ * the specified type. Returns the number of elements in the array.
|
||||
+ *
|
||||
+ * This method should be safer implementation of blobmsg_check_array.
|
||||
+ * It will limit all memory access performed on the blob to the
|
||||
+ * range [attr, attr + len] (upper bound non inclusive) and is
|
||||
+ * thus suited for checking of untrusted blob attributes.
|
||||
+ */
|
||||
+int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len);
|
||||
+
|
||||
int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
|
||||
struct blob_attr **tb, void *data, unsigned int len);
|
||||
int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
|
||||
@@ -271,5 +318,11 @@ int blobmsg_printf(struct blob_buf *buf,
|
||||
rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \
|
||||
(blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||
rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||
+
|
||||
+#define __blobmsg_for_each_attr(pos, attr, rem) \
|
||||
+ for (pos = (struct blob_attr *) (attr ? blobmsg_data(attr) : NULL); \
|
||||
+ rem >= sizeof(struct blob_attr) && (blob_pad_len(pos) <= rem) && \
|
||||
+ (blob_pad_len(pos) >= sizeof(struct blob_attr)); \
|
||||
+ rem -= blob_pad_len(pos), pos = blob_next(pos))
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
From 44d9e85ef058fbb9981d53218cafdc451afa5535 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Wed, 25 Dec 2019 10:27:59 +0100
|
||||
Subject: blobmsg: fix array out of bounds GCC 10 warning
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fixes following warning reported by GCC 10.0.0 20191203:
|
||||
|
||||
blobmsg.c:234:2: error: 'strcpy' offset 6 from the object at 'attr' is out of the bounds of referenced subobject 'name' with type 'uint8_t[0]' {aka 'unsigned char[0]'} at offset 6 [-Werror=array-bounds]
|
||||
234 | strcpy((char *) hdr->name, (const char *)name);
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In file included from blobmsg.c:16:
|
||||
blobmsg.h:42:10: note: subobject 'name' declared here
|
||||
42 | uint8_t name[];
|
||||
| ^~~~
|
||||
|
||||
Reported-by: Khem Raj <raj.khem@gmail.com>
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -246,7 +246,10 @@ blobmsg_new(struct blob_buf *buf, int ty
|
||||
attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);
|
||||
hdr = blob_data(attr);
|
||||
hdr->namelen = cpu_to_be16(namelen);
|
||||
- strcpy((char *) hdr->name, (const char *)name);
|
||||
+
|
||||
+ memcpy(hdr->name, name, namelen);
|
||||
+ hdr->name[namelen] = '\0';
|
||||
+
|
||||
pad_end = *data = blobmsg_data(attr);
|
||||
pad_start = (char *) &hdr->name[namelen];
|
||||
if (pad_start < pad_end)
|
||||
@@ -1,38 +0,0 @@
|
||||
From d0f05d5e6873b30315127d47abbf4ac9f3c8bfb7 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Sat, 28 Dec 2019 19:00:39 +0100
|
||||
Subject: blobmsg: fix wrong payload len passed from blobmsg_check_array
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fix incorrect use of blob_raw_len() on passed blobmsg to
|
||||
blobmsg_check_array_len() introduced in commit b0e21553ae8c ("blobmsg:
|
||||
add _len variants for all attribute checking methods") by using correct
|
||||
blobmsg_len().
|
||||
|
||||
This wrong (higher) length was then for example causing issues in
|
||||
procd's instance_config_parse_command() where blobmsg_check_attr_list()
|
||||
was failing sanity checking of service command, thus resulting in the
|
||||
startup failures of some services like collectd, nlbwmon and samba4.
|
||||
|
||||
Ref: http://lists.infradead.org/pipermail/openwrt-devel/2019-December/020840.html
|
||||
Fixes: b0e21553ae8c ("blobmsg: add _len variants for all attribute checking methods")
|
||||
Reported-by: Hannu Nyman <hannu.nyman@welho.com>
|
||||
Tested-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -101,7 +101,7 @@ bool blobmsg_check_attr_len(const struct
|
||||
|
||||
int blobmsg_check_array(const struct blob_attr *attr, int type)
|
||||
{
|
||||
- return blobmsg_check_array_len(attr, type, blob_raw_len(attr));
|
||||
+ return blobmsg_check_array_len(attr, type, blobmsg_len(attr));
|
||||
}
|
||||
|
||||
int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len)
|
||||
@@ -1,61 +0,0 @@
|
||||
From 31778937b4153492955495e550435c8bbf7cfde8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Tue, 14 Jan 2020 08:55:34 +0100
|
||||
Subject: jshn: prefer snprintf usage
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Better safe than sorry.
|
||||
|
||||
Reviewed-by: Jo-Philipp Wich <jo@mein.io>
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
jshn.c | 16 +++++++++-------
|
||||
1 file changed, 9 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/jshn.c
|
||||
+++ b/jshn.c
|
||||
@@ -68,7 +68,7 @@ static int add_json_array(struct array_l
|
||||
int ret;
|
||||
|
||||
for (i = 0, len = array_list_length(a); i < len; i++) {
|
||||
- sprintf(seq, "%d", i);
|
||||
+ snprintf(seq, sizeof(seq), "%d", i);
|
||||
ret = add_json_element(seq, array_list_get_idx(a, i));
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -197,25 +197,27 @@ static char *getenv_avl(const char *key)
|
||||
static char *get_keys(const char *prefix)
|
||||
{
|
||||
char *keys;
|
||||
+ size_t len = var_prefix_len + strlen(prefix) + sizeof("K_") + 1;
|
||||
|
||||
- keys = alloca(var_prefix_len + strlen(prefix) + sizeof("K_") + 1);
|
||||
- sprintf(keys, "%sK_%s", var_prefix, prefix);
|
||||
+ keys = alloca(len);
|
||||
+ snprintf(keys, len, "%sK_%s", var_prefix, prefix);
|
||||
return getenv_avl(keys);
|
||||
}
|
||||
|
||||
static void get_var(const char *prefix, const char **name, char **var, char **type)
|
||||
{
|
||||
char *tmpname, *varname;
|
||||
+ size_t len = var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("T_");
|
||||
|
||||
- tmpname = alloca(var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("T_"));
|
||||
+ tmpname = alloca(len);
|
||||
|
||||
- sprintf(tmpname, "%s%s_%s", var_prefix, prefix, *name);
|
||||
+ snprintf(tmpname, len, "%s%s_%s", var_prefix, prefix, *name);
|
||||
*var = getenv_avl(tmpname);
|
||||
|
||||
- sprintf(tmpname, "%sT_%s_%s", var_prefix, prefix, *name);
|
||||
+ snprintf(tmpname, len, "%sT_%s_%s", var_prefix, prefix, *name);
|
||||
*type = getenv_avl(tmpname);
|
||||
|
||||
- sprintf(tmpname, "%sN_%s_%s", var_prefix, prefix, *name);
|
||||
+ snprintf(tmpname, len, "%sN_%s_%s", var_prefix, prefix, *name);
|
||||
varname = getenv_avl(tmpname);
|
||||
if (varname)
|
||||
*name = varname;
|
||||
@@ -1,38 +0,0 @@
|
||||
From 935bb933e4a74de7326a4373340fd50655712334 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Tue, 14 Jan 2020 08:57:05 +0100
|
||||
Subject: blobmsg: blobmsg_vprintf: prefer vsnprintf
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Better safe than sorry and while at it add handling of possible
|
||||
*printf() failures.
|
||||
|
||||
Reviewed-by: Jo-Philipp Wich <jo@mein.io>
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -296,10 +296,17 @@ blobmsg_vprintf(struct blob_buf *buf, co
|
||||
len = vsnprintf(&cbuf, sizeof(cbuf), format, arg2);
|
||||
va_end(arg2);
|
||||
|
||||
+ if (len < 0)
|
||||
+ return -1;
|
||||
+
|
||||
sbuf = blobmsg_alloc_string_buffer(buf, name, len + 1);
|
||||
if (!sbuf)
|
||||
return -1;
|
||||
- ret = vsprintf(sbuf, format, arg);
|
||||
+
|
||||
+ ret = vsnprintf(sbuf, len + 1, format, arg);
|
||||
+ if (ret < 0)
|
||||
+ return -1;
|
||||
+
|
||||
blobmsg_add_string_buffer(buf);
|
||||
|
||||
return ret;
|
||||
@@ -1,41 +0,0 @@
|
||||
From 1cc755d7c3989b399bf0c60535a858d22819ca27 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Sun, 12 Jan 2020 22:40:18 +0100
|
||||
Subject: blobmsg_json: fix int16 serialization
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
int16 blobmsg type is currently being serialized as uint16_t due to
|
||||
missing cast during JSON output.
|
||||
|
||||
Following blobmsg content:
|
||||
|
||||
bar-min: -32768 (i16)
|
||||
bar-max: 32767 (i16)
|
||||
|
||||
Produces following JSON:
|
||||
|
||||
{ "bar-min":32768,"bar-max":32767 }
|
||||
|
||||
Whereas one would expect:
|
||||
|
||||
{ "bar-min":-32768,"bar-max":32767 }
|
||||
|
||||
Reviewed-by: Jo-Philipp Wich <jo@mein.io>
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg_json.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/blobmsg_json.c
|
||||
+++ b/blobmsg_json.c
|
||||
@@ -250,7 +250,7 @@ static void blobmsg_format_element(struc
|
||||
sprintf(buf, "%s", *(uint8_t *)data ? "true" : "false");
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT16:
|
||||
- sprintf(buf, "%d", be16_to_cpu(*(uint16_t *)data));
|
||||
+ sprintf(buf, "%d", (int16_t) be16_to_cpu(*(uint16_t *)data));
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT32:
|
||||
sprintf(buf, "%d", (int32_t) be32_to_cpu(*(uint32_t *)data));
|
||||
@@ -1,66 +0,0 @@
|
||||
From 0e330ec3662795aea42ac36ecf7a9f32a249c36d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Tue, 14 Jan 2020 09:05:02 +0100
|
||||
Subject: blobmsg_json: prefer snprintf usage
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Better safe than sorry and while at it prefer use of PRId16 and PRId32
|
||||
formatting constants as well.
|
||||
|
||||
Reviewed-by: Jo-Philipp Wich <jo@mein.io>
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg_json.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/blobmsg_json.c
|
||||
+++ b/blobmsg_json.c
|
||||
@@ -203,7 +203,7 @@ static void blobmsg_format_string(struct
|
||||
buf[1] = escape;
|
||||
|
||||
if (escape == 'u') {
|
||||
- sprintf(buf + 4, "%02x", (unsigned char) *p);
|
||||
+ snprintf(buf + 4, sizeof(buf) - 4, "%02x", (unsigned char) *p);
|
||||
len = 6;
|
||||
} else {
|
||||
len = 2;
|
||||
@@ -220,7 +220,7 @@ static void blobmsg_format_json_list(str
|
||||
static void blobmsg_format_element(struct strbuf *s, struct blob_attr *attr, bool without_name, bool head)
|
||||
{
|
||||
const char *data_str;
|
||||
- char buf[32];
|
||||
+ char buf[317];
|
||||
void *data;
|
||||
int len;
|
||||
|
||||
@@ -244,22 +244,22 @@ static void blobmsg_format_element(struc
|
||||
data_str = buf;
|
||||
switch(blob_id(attr)) {
|
||||
case BLOBMSG_TYPE_UNSPEC:
|
||||
- sprintf(buf, "null");
|
||||
+ snprintf(buf, sizeof(buf), "null");
|
||||
break;
|
||||
case BLOBMSG_TYPE_BOOL:
|
||||
- sprintf(buf, "%s", *(uint8_t *)data ? "true" : "false");
|
||||
+ snprintf(buf, sizeof(buf), "%s", *(uint8_t *)data ? "true" : "false");
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT16:
|
||||
- sprintf(buf, "%d", (int16_t) be16_to_cpu(*(uint16_t *)data));
|
||||
+ snprintf(buf, sizeof(buf), "%" PRId16, (int16_t) be16_to_cpu(*(uint16_t *)data));
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT32:
|
||||
- sprintf(buf, "%d", (int32_t) be32_to_cpu(*(uint32_t *)data));
|
||||
+ snprintf(buf, sizeof(buf), "%" PRId32, (int32_t) be32_to_cpu(*(uint32_t *)data));
|
||||
break;
|
||||
case BLOBMSG_TYPE_INT64:
|
||||
- sprintf(buf, "%" PRId64, (int64_t) be64_to_cpu(*(uint64_t *)data));
|
||||
+ snprintf(buf, sizeof(buf), "%" PRId64, (int64_t) be64_to_cpu(*(uint64_t *)data));
|
||||
break;
|
||||
case BLOBMSG_TYPE_DOUBLE:
|
||||
- sprintf(buf, "%lf", blobmsg_get_double(attr));
|
||||
+ snprintf(buf, sizeof(buf), "%lf", blobmsg_get_double(attr));
|
||||
break;
|
||||
case BLOBMSG_TYPE_STRING:
|
||||
blobmsg_format_string(s, data);
|
||||
@@ -1,110 +0,0 @@
|
||||
From 6289e2d29883d5d9510b6a15c18c597478967a42 Mon Sep 17 00:00:00 2001
|
||||
From: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
|
||||
Date: Sun, 12 Jan 2020 12:26:18 +0100
|
||||
Subject: blobmsg: blobmsg_parse and blobmsg_parse_array oob read fixes
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fix out of bounds read in blobmsg_parse and blobmsg_check_name. The
|
||||
out of bounds read happens because blob_attr and blobmsg_hdr have
|
||||
flexible array members, whose size is 0 in the corresponding sizeofs.
|
||||
For example the __blob_for_each_attr macro checks whether rem >=
|
||||
sizeof(struct blob_attr). However, what LibFuzzer discovered was,
|
||||
if the input data was only 4 bytes, the data would be casted to blob_attr,
|
||||
and later on blob_data(attr) would be called even though attr->data was empty.
|
||||
The same issue could appear with data larger than 4 bytes, where data
|
||||
wasn't empty, but contained only the start of the blobmsg_hdr struct,
|
||||
and blobmsg_hdr name was empty. The bugs were discovered by fuzzing
|
||||
blobmsg_parse and blobmsg_array_parse with LibFuzzer.
|
||||
|
||||
CC: Luka Perkov <luka.perkov@sartura.hr>
|
||||
Reviewed-by: Jo-Philipp Wich <jo@mein.io>
|
||||
Signed-off-by: Juraj Vijtiuk <juraj.vijtiuk@sartura.hr>
|
||||
[refactored some checks, added fuzz inputs, adjusted unit test results]
|
||||
Signed-off-by: Petr Štetiar <ynezz@true.cz>
|
||||
---
|
||||
blobmsg.c | 40 ++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 32 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -36,16 +36,38 @@ bool blobmsg_check_attr(const struct blo
|
||||
return blobmsg_check_attr_len(attr, name, blob_raw_len(attr));
|
||||
}
|
||||
|
||||
+static const struct blobmsg_hdr* blobmsg_hdr_from_blob(const struct blob_attr *attr, size_t len)
|
||||
+{
|
||||
+ if (len < sizeof(struct blob_attr) + sizeof(struct blobmsg_hdr))
|
||||
+ return NULL;
|
||||
+
|
||||
+ return blob_data(attr);
|
||||
+}
|
||||
+
|
||||
+static bool blobmsg_hdr_valid_namelen(const struct blobmsg_hdr *hdr, size_t len)
|
||||
+{
|
||||
+ if (len < sizeof(struct blob_attr) + sizeof(struct blobmsg_hdr) + blobmsg_namelen(hdr) + 1)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
static bool blobmsg_check_name(const struct blob_attr *attr, size_t len, bool name)
|
||||
{
|
||||
char *limit = (char *) attr + len;
|
||||
const struct blobmsg_hdr *hdr;
|
||||
|
||||
- hdr = blob_data(attr);
|
||||
+ hdr = blobmsg_hdr_from_blob(attr, len);
|
||||
+ if (!hdr)
|
||||
+ return false;
|
||||
+
|
||||
if (name && !hdr->namelen)
|
||||
return false;
|
||||
|
||||
- if ((char *) hdr->name + blobmsg_namelen(hdr) > limit)
|
||||
+ if (name && !blobmsg_hdr_valid_namelen(hdr, len))
|
||||
+ return false;
|
||||
+
|
||||
+ if ((char *) hdr->name + blobmsg_namelen(hdr) + 1 > limit)
|
||||
return false;
|
||||
|
||||
if (blobmsg_namelen(hdr) > (blob_len(attr) - sizeof(struct blobmsg_hdr)))
|
||||
@@ -79,9 +101,6 @@ bool blobmsg_check_attr_len(const struct
|
||||
size_t data_len;
|
||||
int id;
|
||||
|
||||
- if (len < sizeof(struct blob_attr))
|
||||
- return false;
|
||||
-
|
||||
if (!blobmsg_check_name(attr, len, name))
|
||||
return false;
|
||||
|
||||
@@ -176,11 +195,10 @@ int blobmsg_parse_array(const struct blo
|
||||
return 0;
|
||||
}
|
||||
|
||||
-
|
||||
int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
|
||||
struct blob_attr **tb, void *data, unsigned int len)
|
||||
{
|
||||
- struct blobmsg_hdr *hdr;
|
||||
+ const struct blobmsg_hdr *hdr;
|
||||
struct blob_attr *attr;
|
||||
uint8_t *pslen;
|
||||
int i;
|
||||
@@ -197,7 +215,13 @@ int blobmsg_parse(const struct blobmsg_p
|
||||
}
|
||||
|
||||
__blob_for_each_attr(attr, data, len) {
|
||||
- hdr = blob_data(attr);
|
||||
+ hdr = blobmsg_hdr_from_blob(attr, len);
|
||||
+ if (!hdr)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (!blobmsg_hdr_valid_namelen(hdr, len))
|
||||
+ return -1;
|
||||
+
|
||||
for (i = 0; i < policy_len; i++) {
|
||||
if (!policy[i].name)
|
||||
continue;
|
||||
@@ -1,33 +0,0 @@
|
||||
From 75e300aeec25e032a9778bea34c713969960d1f0 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Nisbet <nischris@gmail.com>
|
||||
Date: Wed, 12 Feb 2020 21:00:31 +1300
|
||||
Subject: [PATCH] blobmsg: fix wrong payload len passed from
|
||||
blobmsg_check_array
|
||||
|
||||
Fix incorrect use of blobmsg_len() on passed blobmsg to
|
||||
blobmsg_check_array_len() introduced in commit 379cd33d1992
|
||||
("fix wrong payload len passed from blobmsg_check_array") by using correct
|
||||
blob_len().
|
||||
|
||||
By using blobmsg_len() a value too small was passed to blobmsg_check_array()
|
||||
which could lead to this function returning an error when there is none.
|
||||
|
||||
Fixes: 379cd33d1992 ("fix wrong payload len passed from blobmsg_check_array")
|
||||
Signed-off-by: Chris Nisbet <nischris@gmail.com>
|
||||
[add fixes tag, rewrap commit message]
|
||||
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
||||
---
|
||||
blobmsg.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/blobmsg.c
|
||||
+++ b/blobmsg.c
|
||||
@@ -120,7 +120,7 @@ bool blobmsg_check_attr_len(const struct
|
||||
|
||||
int blobmsg_check_array(const struct blob_attr *attr, int type)
|
||||
{
|
||||
- return blobmsg_check_array_len(attr, type, blobmsg_len(attr));
|
||||
+ return blobmsg_check_array_len(attr, type, blob_len(attr));
|
||||
}
|
||||
|
||||
int blobmsg_check_array_len(const struct blob_attr *attr, int type, size_t len)
|
||||
@@ -1,38 +0,0 @@
|
||||
From c42f11cc7c0f0ec6571af06ada6ff0e8882f4fde Mon Sep 17 00:00:00 2001
|
||||
From: =?utf8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Tue, 19 Nov 2019 12:34:14 +0100
|
||||
Subject: [PATCH] jshn: main: fix leak of memory pointed to by 'vars'
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fixes following leak of memory:
|
||||
|
||||
6,016 bytes in 1 blocks are possibly lost in loss record 1 of 1
|
||||
at 0x4C31B25: calloc
|
||||
by 0x1098F8: main (jshn.c:353)
|
||||
|
||||
Signed-off-by: Petr Å tetiar <ynezz@true.cz>
|
||||
---
|
||||
jshn.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/jshn.c b/jshn.c
|
||||
index 2d1748e..00293f2 100644
|
||||
--- a/jshn.c
|
||||
+++ b/jshn.c
|
||||
@@ -410,8 +410,11 @@
|
||||
indent = true;
|
||||
break;
|
||||
default:
|
||||
+ free(vars);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ free(vars);
|
||||
return usage(argv[0]);
|
||||
}
|
||||
--
|
||||
2.20.1
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
From cb698e35409b898aedbbc3c673a0055dc1520ef6 Mon Sep 17 00:00:00 2001
|
||||
From: =?utf8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
|
||||
Date: Tue, 19 Nov 2019 14:09:43 +0100
|
||||
Subject: [PATCH 1/1] jshn: jshn_parse: fix leaks of memory pointed to by 'obj'
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fixes following leaks of memory:
|
||||
|
||||
352 (72 direct, 280 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
|
||||
at 0x4C31B25: calloc
|
||||
by 0x5042E1F: json_object_new_array
|
||||
by 0x5044B02: json_tokener_parse_ex
|
||||
by 0x5045316: json_tokener_parse_verbose
|
||||
by 0x504537D: json_tokener_parse
|
||||
by 0x401AA9: jshn_parse (jshn.c:179)
|
||||
by 0x401977: main (jshn.c:378)
|
||||
|
||||
752 (72 direct, 680 indirect) bytes in 1 blocks are definitely lost in loss record 6 of 6
|
||||
at 0x4C31B25: calloc
|
||||
by 0x50424CF: json_object_new_object
|
||||
by 0x5044B38: json_tokener_parse_ex
|
||||
by 0x5045316: json_tokener_parse_verbose
|
||||
by 0x504537D: json_tokener_parse
|
||||
by 0x401AA9: jshn_parse (jshn.c:179)
|
||||
by 0x401977: main (jshn.c:380)
|
||||
|
||||
Signed-off-by: Petr Å tetiar <ynezz@true.cz>
|
||||
---
|
||||
jshn.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/jshn.c b/jshn.c
|
||||
index 2eebe6c..9639951 100644
|
||||
--- a/jshn.c
|
||||
+++ b/jshn.c
|
||||
@@ -178,12 +178,15 @@ static int jshn_parse(const char *str)
|
||||
|
||||
obj = json_tokener_parse(str);
|
||||
if (!obj || json_object_get_type(obj) != json_type_object) {
|
||||
+ if (obj)
|
||||
+ json_object_put(obj);
|
||||
fprintf(stderr, "Failed to parse message data\n");
|
||||
return 1;
|
||||
}
|
||||
fprintf(stdout, "json_init;\n");
|
||||
add_json_object(obj);
|
||||
fflush(stdout);
|
||||
+ json_object_put(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.20.1
|
||||
|
||||
98
package/lienol/luci-app-nginx-pingos/Makefile
Normal file
98
package/lienol/luci-app-nginx-pingos/Makefile
Normal file
@@ -0,0 +1,98 @@
|
||||
# Copyright (C) 2020 Lienol <lawlienol@gmail.com>
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-nginx-pingos
|
||||
PKG_VERSION:=1.19.0
|
||||
PKG_RELEASE:=3
|
||||
|
||||
PKG_SOURCE:=nginx-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://nginx.org/download/
|
||||
PKG_HASH:=44a616171fcd7d7ad7c6af3e6f3ad0879b54db5a5d21be874cd458b5691e36c8
|
||||
|
||||
PKG_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
PKG_BUILD_DIR:=$(PKG_DIR)/nginx-$(PKG_VERSION)
|
||||
|
||||
PKG_FIXUP:=autoreconf
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_INSTALL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
CATEGORY:=LuCI
|
||||
SUBMENU:=3. Applications
|
||||
TITLE:=PingOS server
|
||||
PKGARCH:=all
|
||||
URL:=https://pingos.io/
|
||||
DEPENDS:=+libpcre +libopenssl +zlib +libpthread
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
rm -r $(PKG_BUILD_DIR)
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
tar -zxvf $(DL_DIR)/$(PKG_SOURCE) -C $(PKG_DIR)
|
||||
$(CP) -pR ./modules $(PKG_BUILD_DIR)/modules
|
||||
$(call Build/Prepare/Default,)
|
||||
endef
|
||||
|
||||
ADDITIONAL_MODULES:= --with-http_ssl_module \
|
||||
--add-module=./modules/nginx-rtmp-module \
|
||||
--add-module=./modules/nginx-client-module \
|
||||
--add-module=./modules/nginx-multiport-module \
|
||||
--add-module=./modules/nginx-toolkit-module
|
||||
|
||||
TARGET_CFLAGS += -fvisibility=hidden -ffunction-sections -fdata-sections -DNGX_LUA_NO_BY_LUA_BLOCK
|
||||
TARGET_LDFLAGS += -Wl,--gc-sections
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--crossbuild=Linux::$(ARCH) \
|
||||
--prefix=/usr \
|
||||
--conf-path=/usr/share/pingos/conf/nginx.conf \
|
||||
$(ADDITIONAL_MODULES) \
|
||||
--error-log-path=/var/etc/pingos/error.log \
|
||||
--pid-path=/var/etc/pingos/pingos.pid \
|
||||
--lock-path=/var/etc/pingos/pingos.lock \
|
||||
--http-log-path=/var/etc/pingos/access.log \
|
||||
--http-client-body-temp-path=/var/etc/pingos/lib/body \
|
||||
--http-proxy-temp-path=/var/etc/pingos/lib/proxy \
|
||||
--with-cc="$(TARGET_CC)" \
|
||||
--with-cc-opt="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \
|
||||
--with-ld-opt="$(TARGET_LDFLAGS)" \
|
||||
--without-http_upstream_zone_module
|
||||
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/etc
|
||||
$(INSTALL_CONF) ./root/etc/pingos.template $(1)/etc/pingos.template
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./root/etc/config/pingos $(1)/etc/config/pingos
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./root/etc/init.d/pingos $(1)/etc/init.d/pingos
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/uci-defaults
|
||||
$(INSTALL_CONF) ./root/etc/uci-defaults/* $(1)/etc/uci-defaults
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/pingos
|
||||
cp -pR $(PKG_INSTALL_DIR)/usr/share/pingos/conf $(1)/usr/share/pingos
|
||||
$(INSTALL_DATA) ./root/resource/conf-template/nginx.conf $(1)/usr/share/pingos/conf/nginx.conf
|
||||
|
||||
cp -pR $(PKG_INSTALL_DIR)/usr/html $(1)/usr/share/pingos/html
|
||||
$(INSTALL_DATA) ./root/resource/crossdomain.xml $(1)/usr/share/pingos/html/crossdomain.xml
|
||||
$(INSTALL_DATA) ./root/resource/stat.xsl $(1)/usr/share/pingos/html/stat.xsl
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
|
||||
cp -pR ./luasrc/* $(1)/usr/lib/lua/luci/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
|
||||
po2lmo ./po/zh-cn/pingos.po $(1)/usr/lib/lua/luci/i18n/pingos.zh-cn.lmo
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/nginx $(1)/usr/sbin/pingos
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
@@ -0,0 +1,17 @@
|
||||
-- Copyright 2020 Lienol <lawlienol@gmail.com>
|
||||
module("luci.controller.pingos", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/pingos") then return end
|
||||
|
||||
entry({"admin", "nas"}, firstchild(), "NAS", 44).dependent = false
|
||||
entry({"admin", "nas", "pingos"}, cbi("pingos"), _("PingOS"), 3).dependent = true
|
||||
entry({"admin", "nas", "pingos", "status"}, call("act_status")).leaf = true
|
||||
end
|
||||
|
||||
function act_status()
|
||||
local e = {}
|
||||
e.status = luci.sys.call("ps -w | grep pingos | grep nginx | grep -v grep > /dev/null") == 0
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
m = Map("pingos", translate("PingOS"))
|
||||
m:append(Template("pingos/status"))
|
||||
|
||||
s = m:section(TypedSection, "global")
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
s:tab("global", translate("Global Settings"))
|
||||
s:tab("template", translate("Edit Template"))
|
||||
|
||||
nginx = s:taboption("template", Value, "_nginx", translatef("Edit the template that is used for generating the %s configuration.", "nginx"),
|
||||
translatef("This is the content of the file '%s'", "/etc/pingos.template") .. "<br />" ..
|
||||
translatef("Values enclosed by pipe symbols ('|') should not be changed. They get their values from the '%s' tab.", translate("Global Settings")))
|
||||
nginx.template = "cbi/tvalue"
|
||||
nginx.rows = 30
|
||||
|
||||
function nginx.cfgvalue(self, section)
|
||||
return nixio.fs.readfile("/etc/pingos.template")
|
||||
end
|
||||
|
||||
function nginx.write(self, section, value)
|
||||
value = value:gsub("\r\n?", "\n")
|
||||
nixio.fs.writefile("/etc/pingos.template", value)
|
||||
end
|
||||
|
||||
o = s:taboption("global", Flag, "enable", translate("Enable"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", Value, "http_port", "HTTP(S)" ..translate("Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 8082
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", Flag, "https", translate("HTTPS"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", FileUpload, "certificate", translate("certificate"))
|
||||
o:depends("https", 1)
|
||||
|
||||
o = s:taboption("global", FileUpload, "key", translate("key"))
|
||||
o:depends("https", 1)
|
||||
|
||||
o = s:taboption("global", Value, "rtmp_port", "RTMP" ..translate("Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 1935
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", Flag, "hls", translate("HLS"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", Flag, "hls2", translate("HLS2"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", Flag, "ts_record", "TS " .. translate("Record"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", Flag, "flv_record", "FLV " .. translate("Record"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:taboption("global", Value, "record_path", translate("Record") .. translate("Path"))
|
||||
o.default = "/tmp/record"
|
||||
o:depends("ts_record", 1)
|
||||
o:depends("flv_record", 1)
|
||||
|
||||
return m
|
||||
@@ -0,0 +1,52 @@
|
||||
<fieldset class="cbi-section">
|
||||
<legend><%:Running Status%></legend>
|
||||
<fieldset class="cbi-section">
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title">Nginx <%:Status%></label>
|
||||
<div class="cbi-value-field" id="_nginx_status"><%:Collecting data...%></div>
|
||||
</div>
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"></label>
|
||||
<div class="cbi-value-field">
|
||||
<font color="red" id="tips"></font>
|
||||
<ul id="tips2">
|
||||
<li>rtmp rtmp://ip/live/<%:Stream name%></li>
|
||||
<li>http(s)-flv http(s)://ip/flv/<%:Stream name%></li>
|
||||
<li>hls http(s)://ip/hls/<%:Stream name%>.m3u8</li>
|
||||
<li>hls+ http(s)://ip/hls2/<%:Stream name%>.m3u8</li>
|
||||
<li>http(s)-ts http(s)://ip/ts/<%:Stream name%></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var nginx_status = document.getElementById('_nginx_status');
|
||||
XHR.poll(3, '<%=url([[admin]], [[nas]], [[pingos]], [[status]])%>', null,
|
||||
function(x, json) {
|
||||
if (x && x.status == 200) {
|
||||
if (nginx_status) {
|
||||
var str = "";
|
||||
if (json.status) {
|
||||
document.getElementById("tips").innerHTML = '<%:If you need external network access, please open the port by yourself.%>';
|
||||
str = '<font color="green"><%:RUNNING%> ✓</font><input type="button" class="cbi-button cbi-input-apply" value="<%:Enter interface%>" onclick="open_web()" />'
|
||||
} else {
|
||||
document.getElementById("tips").innerHTML = '';
|
||||
str = '<font color="red"><%:NOT RUNNING%> X</font>';
|
||||
}
|
||||
nginx_status.innerHTML = str;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
function open_web(){
|
||||
var port = '<%=luci.sys.exec("uci -q get pingos.@global[0].http_port"):gsub("^%s*(.-)%s*$", "%1")%>';
|
||||
var ishttps = '<%=luci.sys.exec("uci -q get pingos.@global[0].https"):gsub("^%s*(.-)%s*$", "%1")%>';
|
||||
var protocol = (ishttps == "1") ? "https://" : "http://";
|
||||
var hostname = location.hostname;
|
||||
|
||||
var url = protocol + hostname + ":" + port;
|
||||
window.open(url, 'target', '');
|
||||
}
|
||||
//]]></script>
|
||||
@@ -0,0 +1,24 @@
|
||||
Copyright (C) 2016-2020, by Jie Wu "AlexWoo" <wj19840501@gmail.com>.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
ngx_addon_name=ngx_client_module
|
||||
|
||||
|
||||
CORE_MODULES="$CORE_MODULES \
|
||||
ngx_client_module \
|
||||
ngx_http_client_module \
|
||||
"
|
||||
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
|
||||
$ngx_addon_dir/ngx_client.c \
|
||||
$ngx_addon_dir/ngx_http_client.c \
|
||||
"
|
||||
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
|
||||
$ngx_addon_dir/ngx_client.h \
|
||||
$ngx_addon_dir/ngx_http_client.h \
|
||||
"
|
||||
|
||||
CFLAGS="$CFLAGS -I $ngx_addon_dir"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_CLIENT_H_INCLUDED_
|
||||
#define _NGX_CLIENT_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
typedef struct ngx_client_session_s ngx_client_session_t;
|
||||
|
||||
typedef void (* ngx_client_connect_pt)(ngx_client_session_t *s);
|
||||
typedef void (* ngx_client_recv_pt)(ngx_client_session_t *s);
|
||||
typedef void (* ngx_client_send_pt)(ngx_client_session_t *s);
|
||||
typedef void (* ngx_client_closed_pt)(ngx_client_session_t *s);
|
||||
|
||||
|
||||
struct ngx_client_session_s {
|
||||
ngx_peer_connection_t peer;
|
||||
ngx_str_t server; /* server original address */
|
||||
in_port_t port; /* server port */
|
||||
|
||||
ngx_connection_t *connection;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
ngx_log_t log;
|
||||
|
||||
void *data; /* save ctx for callback */
|
||||
|
||||
ngx_chain_t *out; /* save data unsend */
|
||||
|
||||
/* configured part */
|
||||
|
||||
/* timer for connecting to server */
|
||||
ngx_msec_t connect_timeout;
|
||||
|
||||
/* timer for sending buffer full */
|
||||
ngx_msec_t send_timeout;
|
||||
|
||||
/*
|
||||
* data will be postponed until nginx has at least
|
||||
* postpone_output bytes of data to send
|
||||
*/
|
||||
size_t postpone_output;
|
||||
|
||||
/* use dynamic resolver mechanism for resolving domain */
|
||||
unsigned dynamic_resolver:1;
|
||||
|
||||
unsigned tcp_nodelay:1; /* TCP_NODELAY */
|
||||
unsigned tcp_nopush:1; /* TCP_CORK */
|
||||
|
||||
/* runtime part */
|
||||
|
||||
size_t recv; /* client recv bytes */
|
||||
|
||||
unsigned connected:1; /* client connected to server */
|
||||
unsigned closed:1; /* client has been closed */
|
||||
|
||||
ngx_event_t close; /* for async close */
|
||||
|
||||
/* callback */
|
||||
|
||||
ngx_client_connect_pt client_connected; /* connect successd */
|
||||
ngx_client_recv_pt client_recv; /* recv msg from peer */
|
||||
ngx_client_send_pt client_send; /* send msg to peer */
|
||||
ngx_client_closed_pt client_closed; /* finalize connection */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* create a client session
|
||||
*
|
||||
* return value:
|
||||
* return client session for successd, return NULL for failed
|
||||
* paras:
|
||||
* peer: server address and port, address could be domain or ip
|
||||
* local: set if need to bind local address, or set NULL
|
||||
* udp: set 1, use udp, set 0, use tcp
|
||||
* log: for logging error when create client session failed
|
||||
*/
|
||||
ngx_client_session_t *ngx_client_create(ngx_str_t *peer, ngx_str_t *local,
|
||||
ngx_flag_t udp, ngx_log_t *log);
|
||||
|
||||
|
||||
/*
|
||||
* connect to client server, should use client session created by
|
||||
* ngx_client_create. before connect to server, user can set paras in
|
||||
* configured part.
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
* paras:
|
||||
* s: client session created by ngx_client_create
|
||||
*/
|
||||
void ngx_client_connect(ngx_client_session_t *s);
|
||||
|
||||
|
||||
/*
|
||||
* send data to server
|
||||
*
|
||||
* return value:
|
||||
* NGX_ERROR: write error, client session will be closed
|
||||
* NGX_AGAIN: data not sent completely, it will save in client session out
|
||||
* NGX_OK: data sent completely
|
||||
* paras:
|
||||
* s: client session
|
||||
* out: data for sending
|
||||
*/
|
||||
ngx_int_t ngx_client_write(ngx_client_session_t *s, ngx_chain_t *out);
|
||||
|
||||
|
||||
/*
|
||||
* read data from server
|
||||
*
|
||||
* return value:
|
||||
* NGX_ERROR: read error, client session will be closed
|
||||
* NGX_DECLINED: buf for receiving data is full
|
||||
* NGX_AGAIN: no data for reading
|
||||
* 0: server closed
|
||||
* >0: bytes read into buffer
|
||||
* paras:
|
||||
* s: client session
|
||||
* b: buffer for receiving data
|
||||
*/
|
||||
ngx_int_t ngx_client_read(ngx_client_session_t *s, ngx_buf_t *b);
|
||||
|
||||
|
||||
/*
|
||||
* keepalive client connection, and destroy session
|
||||
* if use client connect the same ip:port,
|
||||
* new client session will reuse the connection
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
* paras:
|
||||
* s: client session
|
||||
*/
|
||||
void ngx_client_set_keepalive(ngx_client_session_t *s);
|
||||
|
||||
|
||||
/*
|
||||
* close client session
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
* paras:
|
||||
* s: client session
|
||||
*/
|
||||
void ngx_client_close(ngx_client_session_t *s);
|
||||
|
||||
|
||||
/*
|
||||
* paras:
|
||||
* r: http request to query status of client
|
||||
*/
|
||||
ngx_chain_t *ngx_client_state(ngx_http_request_t *r, unsigned detail);
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_CLIENT_H_INCLUDE_
|
||||
#define _NGX_HTTP_CLIENT_H_INCLUDE_
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include "ngx_client.h"
|
||||
#include "ngx_toolkit_misc.h"
|
||||
|
||||
|
||||
// http client method
|
||||
#define NGX_HTTP_CLIENT_GET 0
|
||||
#define NGX_HTTP_CLIENT_HEAD 1
|
||||
#define NGX_HTTP_CLIENT_POST 2
|
||||
#define NGX_HTTP_CLIENT_PUT 3
|
||||
#define NGX_HTTP_CLIENT_DELETE 4
|
||||
#define NGX_HTTP_CLIENT_MKCOL 5
|
||||
#define NGX_HTTP_CLIENT_COPY 6
|
||||
#define NGX_HTTP_CLIENT_MOVE 7
|
||||
#define NGX_HTTP_CLIENT_OPTIONS 8
|
||||
#define NGX_HTTP_CLIENT_PROPFIND 9
|
||||
#define NGX_HTTP_CLIENT_PROPPATCH 10
|
||||
#define NGX_HTTP_CLIENT_LOCK 11
|
||||
#define NGX_HTTP_CLIENT_UNLOCK 12
|
||||
#define NGX_HTTP_CLIENT_PATCH 13
|
||||
#define NGX_HTTP_CLIENT_TRACE 14
|
||||
|
||||
// http client version
|
||||
#define NGX_HTTP_CLIENT_VERSION_9 0
|
||||
#define NGX_HTTP_CLIENT_VERSION_10 1
|
||||
#define NGX_HTTP_CLIENT_VERSION_11 2
|
||||
#define NGX_HTTP_CLIENT_VERSION_20 3
|
||||
|
||||
// http client opt
|
||||
#define NGX_HTTP_CLIENT_OPT_CONNECT_TIMEOUT 0
|
||||
#define NGX_HTTP_CLIENT_OPT_SEND_TIMEOUT 1
|
||||
#define NGX_HTTP_CLIENT_OPT_POSTPONE_OUTPUT 2
|
||||
#define NGX_HTTP_CLIENT_OPT_DYNAMIC_RESOLVER 3
|
||||
#define NGX_HTTP_CLIENT_OPT_TCP_NODELAY 4
|
||||
#define NGX_HTTP_CLIENT_OPT_TCP_NOPUSH 5
|
||||
#define NGX_HTTP_CLIENT_OPT_HEADER_TIMEOUT 6
|
||||
|
||||
|
||||
typedef void (* ngx_http_client_handler_pt)(void *r, ngx_http_request_t *hcr);
|
||||
|
||||
|
||||
/* create and set http request */
|
||||
|
||||
/*
|
||||
* create a http request for sending to server
|
||||
*
|
||||
* return value:
|
||||
* return http request for successd, return NULL for failed
|
||||
*
|
||||
* paras:
|
||||
* log: error in create will use this log
|
||||
* method: http client method
|
||||
* url: full request url like "http://test.com/index.html?hello=world"
|
||||
* headers: http request header for sending
|
||||
* send_body: callback for sending body
|
||||
* request: who send http request
|
||||
*/
|
||||
ngx_http_request_t *ngx_http_client_create(ngx_log_t *log,
|
||||
ngx_uint_t method, ngx_str_t *url, ngx_keyval_t *headers,
|
||||
ngx_http_client_handler_pt send_body, void *request);
|
||||
|
||||
/*
|
||||
* add cleanup as ngx_http_cleanup_add
|
||||
*/
|
||||
ngx_http_cleanup_t *ngx_http_client_cleanup_add(ngx_http_request_t *r,
|
||||
size_t size);
|
||||
|
||||
/*
|
||||
* set read handler for http client, should set before send request,
|
||||
* otherwise body from server will discard
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* read_handler: handler for setting
|
||||
*/
|
||||
void ngx_http_client_set_read_handler(ngx_http_request_t *r,
|
||||
ngx_http_client_handler_pt read_handler);
|
||||
|
||||
/*
|
||||
* set http headers
|
||||
*
|
||||
* return value:
|
||||
* NGX_OK for successd, NGX_ERROR for failed
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* headers: headers set into r
|
||||
* if value is not null, will set or modify the header
|
||||
* if value is null string, will delete the header
|
||||
*/
|
||||
ngx_int_t ngx_http_client_set_headers(ngx_http_request_t *r,
|
||||
ngx_keyval_t *headers);
|
||||
|
||||
/*
|
||||
* set write handler for http client, if set,
|
||||
* will use this handler for sending body,
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* write_handler: handler for setting
|
||||
*/
|
||||
void ngx_http_client_set_write_handler(ngx_http_request_t *r,
|
||||
ngx_http_client_handler_pt write_handler);
|
||||
|
||||
/*
|
||||
* set write handler for http client, if set,
|
||||
* will use this handler for sending body,
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* write_handler: handler for setting
|
||||
*/
|
||||
void ngx_http_client_set_version(ngx_http_request_t *r, ngx_uint_t version);
|
||||
|
||||
/*
|
||||
* set http client option
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* opt: http client opt
|
||||
* NGX_HTTP_CLIENT_OPT_CONNECT_TIMEOUT:
|
||||
* connect server timer
|
||||
* NGX_HTTP_CLIENT_OPT_SEND_TIMEOUT:
|
||||
* send data timer when buffer full
|
||||
* NGX_HTTP_CLIENT_OPT_POSTPONE_OUTPUT:
|
||||
* size threshold to send
|
||||
* NGX_HTTP_CLIENT_OPT_DYNAMIC_RESOLVER:
|
||||
* whether use dynamic resolver to resolv domain
|
||||
* NGX_HTTP_CLIENT_OPT_TCP_NODELAY:
|
||||
* whether set TCP_NODELAY
|
||||
* NGX_HTTP_CLIENT_OPT_TCP_NOPUSH:
|
||||
* whether set TCP_CORK
|
||||
* NGX_HTTP_CLIENT_OPT_HEADER_TIMEOUT:
|
||||
* timer for waiting response header from server
|
||||
* value: http client opt value want to set
|
||||
*/
|
||||
void ngx_http_client_setopt(ngx_http_request_t *r, unsigned opt,
|
||||
ngx_uint_t value);
|
||||
|
||||
/* send http request */
|
||||
|
||||
/*
|
||||
* send http request
|
||||
*
|
||||
* return value:
|
||||
* NGX_OK for successd, NGX_ERROR for failed
|
||||
*
|
||||
* paras:
|
||||
* r: http request for seding, create by ngx_http_client_create
|
||||
*/
|
||||
ngx_int_t ngx_http_client_send(ngx_http_request_t *r);
|
||||
|
||||
/*
|
||||
* create and send http GET request to server
|
||||
*
|
||||
* return value:
|
||||
* return http request for successd, return NULL for failed
|
||||
*
|
||||
* paras:
|
||||
* log: error in create will use this log
|
||||
* url: full request url like "http://test.com/index.html?hello=world"
|
||||
* headers: http request header for sending
|
||||
* request: who send http request
|
||||
*/
|
||||
ngx_http_request_t *ngx_http_client_get(ngx_log_t *log, ngx_str_t *url,
|
||||
ngx_keyval_t *headers, void *request);
|
||||
|
||||
/*
|
||||
* create and send http HEAD request to server
|
||||
*
|
||||
* return value:
|
||||
* return http request for successd, return NULL for failed
|
||||
*
|
||||
* paras:
|
||||
* log: error in create will use this log
|
||||
* url: full request url like "http://test.com/index.html?hello=world"
|
||||
* headers: http request header for sending
|
||||
* request: who send http request
|
||||
*/
|
||||
ngx_http_request_t *ngx_http_client_head(ngx_log_t *log, ngx_str_t *url,
|
||||
ngx_keyval_t *headers, void *request);
|
||||
|
||||
/*
|
||||
* create and send http POST request to server
|
||||
*
|
||||
* return value:
|
||||
* return http request for successd, return NULL for failed
|
||||
*
|
||||
* paras:
|
||||
* log: error in create will use this log
|
||||
* url: full request url like "http://test.com/index.html?hello=world"
|
||||
* headers: http request header for sending
|
||||
* send_body: callback for sending body
|
||||
* request: who send http request
|
||||
*/
|
||||
ngx_http_request_t *ngx_http_client_post(ngx_log_t *log, ngx_str_t *url,
|
||||
ngx_keyval_t *headers, ngx_http_client_handler_pt send_body, void *request);
|
||||
|
||||
|
||||
/* get response */
|
||||
|
||||
/*
|
||||
* get http response version
|
||||
*
|
||||
* return value:
|
||||
* http response version
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
*/
|
||||
ngx_uint_t ngx_http_client_http_version(ngx_http_request_t *r);
|
||||
|
||||
/*
|
||||
* get http response status code
|
||||
*
|
||||
* return value:
|
||||
* http response status code like 200, 500
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
*/
|
||||
ngx_uint_t ngx_http_client_status_code(ngx_http_request_t *r);
|
||||
|
||||
/*
|
||||
* get http response header's value
|
||||
*
|
||||
* return value:
|
||||
* http response header's value
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* key: http header like "Host", "Content-Type"
|
||||
*/
|
||||
ngx_str_t *ngx_http_client_header_in(ngx_http_request_t *r, ngx_str_t *key);
|
||||
|
||||
/*
|
||||
* read http response body
|
||||
*
|
||||
* return value:
|
||||
* NGX_AGAIN: read part of data
|
||||
* 0: tcp connection disconnect, need finalize request with 1
|
||||
* NGX_ERROR: tcp connection error disconnect, need finalize request with 1
|
||||
* NGX_DONE: response body has been read, could finalize request with 0
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* in: where read data put
|
||||
*/
|
||||
ngx_int_t ngx_http_client_read_body(ngx_http_request_t *r, ngx_chain_t **in);
|
||||
|
||||
/*
|
||||
* get receive bytes
|
||||
*
|
||||
* return value:
|
||||
* bytes receive from server
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
*/
|
||||
off_t ngx_http_client_rbytes(ngx_http_request_t *r);
|
||||
|
||||
/*
|
||||
* get send bytes
|
||||
*
|
||||
* return value:
|
||||
* bytes send to server
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
*/
|
||||
off_t ngx_http_client_wbytes(ngx_http_request_t *r);
|
||||
|
||||
|
||||
/* end request */
|
||||
|
||||
/*
|
||||
* detach http client request with it's creator,
|
||||
* all read and write handler will not be triggered
|
||||
*
|
||||
* return value:
|
||||
* bytes send to server
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
*/
|
||||
void ngx_http_client_detach(ngx_http_request_t *r);
|
||||
|
||||
/*
|
||||
* finalize http client request
|
||||
*
|
||||
* return value:
|
||||
* void
|
||||
*
|
||||
* paras:
|
||||
* r: http client request
|
||||
* closed: set to 1, will close connection to server
|
||||
* set to 0, will keep connection to server alive
|
||||
*/
|
||||
void ngx_http_client_finalize_request(ngx_http_request_t *r, ngx_flag_t closed);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
ngx_addon_name=ngx_client_test_module
|
||||
|
||||
HTTP_MODULES="$HTTP_MODULES \
|
||||
ngx_client_test_module \
|
||||
ngx_http_client_test_module \
|
||||
ngx_client_stat_module \
|
||||
"
|
||||
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS
|
||||
$ngx_addon_dir/ngx_client_test_module.c \
|
||||
$ngx_addon_dir/ngx_http_client_test_module.c \
|
||||
$ngx_addon_dir/ngx_client_stat_module.c \
|
||||
"
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
user root;
|
||||
worker_processes 4;
|
||||
|
||||
#error_log logs/error.log;
|
||||
#error_log logs/error.log notice;
|
||||
error_log logs/error.log info;
|
||||
|
||||
#pid logs/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
resolver 192.168.84.254;
|
||||
dynamic_refresh_interval 5m;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
# '$status $body_bytes_sent "$http_referer" '
|
||||
# '"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
#access_log logs/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location /client_test {
|
||||
client_test;
|
||||
}
|
||||
|
||||
location /http_client_test {
|
||||
http_client_test;
|
||||
}
|
||||
|
||||
location /client_stat {
|
||||
client_stat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
#include <ngx_http.h>
|
||||
#include "ngx_client.h"
|
||||
#include "ngx_rbuf.h"
|
||||
#include "ngx_poold.h"
|
||||
#include "ngx_timerd.h"
|
||||
#include "ngx_event_timer_module.h"
|
||||
#include "ngx_event_resolver.h"
|
||||
#include "ngx_dynamic_resolver.h"
|
||||
|
||||
|
||||
static char *ngx_client_stat(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_client_stat_commands[] = {
|
||||
|
||||
{ ngx_string("client_stat"),
|
||||
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
|
||||
ngx_client_stat,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_client_stat_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
NULL, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
NULL, /* create location configuration */
|
||||
NULL /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_client_stat_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_client_stat_module_ctx, /* module context */
|
||||
ngx_client_stat_commands, /* module directives */
|
||||
NGX_HTTP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_client_stat_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_chain_t **ll, *out;
|
||||
ngx_buf_t *b;
|
||||
size_t len;
|
||||
|
||||
r->headers_out.status = NGX_HTTP_OK;
|
||||
ngx_http_send_header(r);
|
||||
|
||||
ll = &out;
|
||||
|
||||
len = sizeof("--------------------------------------------------\n") - 1
|
||||
+ sizeof("ngx_worker: ngx_process_slot: pid: \n") - 1
|
||||
+ 3 * NGX_OFF_T_LEN;
|
||||
|
||||
*ll = ngx_alloc_chain_link(r->pool);
|
||||
if (*ll == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
(*ll)->next = NULL;
|
||||
|
||||
b = ngx_create_temp_buf(r->pool, len);
|
||||
if (b == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
(*ll)->buf = b;
|
||||
|
||||
b->last = ngx_snprintf(b->last, len,
|
||||
"--------------------------------------------------\n"
|
||||
"ngx_worker: %i ngx_process_slot: %i pid: %i\n",
|
||||
ngx_worker, ngx_process_slot, ngx_pid);
|
||||
|
||||
if (*ll) {
|
||||
ll = &(*ll)->next;
|
||||
}
|
||||
*ll = ngx_rbuf_state(r, 1);
|
||||
|
||||
if (*ll) {
|
||||
ll = &(*ll)->next;
|
||||
}
|
||||
*ll = ngx_event_timer_state(r);
|
||||
|
||||
if (*ll) {
|
||||
ll = &(*ll)->next;
|
||||
}
|
||||
*ll = ngx_event_resolver_state(r);
|
||||
|
||||
if (*ll) {
|
||||
ll = &(*ll)->next;
|
||||
}
|
||||
*ll = ngx_dynamic_resolver_state(r);
|
||||
|
||||
if (*ll) {
|
||||
ll = &(*ll)->next;
|
||||
}
|
||||
*ll = ngx_poold_state(r, 1);
|
||||
|
||||
if (*ll) {
|
||||
ll = &(*ll)->next;
|
||||
}
|
||||
*ll = ngx_timerd_state(r, 1);
|
||||
|
||||
if (*ll) {
|
||||
ll = &(*ll)->next;
|
||||
}
|
||||
*ll = ngx_client_state(r, 1);
|
||||
|
||||
(*ll)->buf->last_buf = 1;
|
||||
|
||||
return ngx_http_output_filter(r, out);
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_client_stat(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
|
||||
clcf->handler = ngx_client_stat_handler;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include "ngx_client.h"
|
||||
|
||||
|
||||
static char *ngx_client_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_client_test_commands[] = {
|
||||
|
||||
{ ngx_string("client_test"),
|
||||
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
|
||||
ngx_client_test,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_client_test_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
NULL, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
NULL, /* create location configuration */
|
||||
NULL /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_client_test_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_client_test_module_ctx, /* module context */
|
||||
ngx_client_test_commands, /* module directives */
|
||||
NGX_HTTP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
ngx_client_test_connected(ngx_client_session_t *s)
|
||||
{
|
||||
ngx_buf_t *b;
|
||||
size_t len;
|
||||
ngx_chain_t out;
|
||||
ngx_http_request_t *r;
|
||||
ngx_event_t *wev;
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, &s->log, 0, "client connected");
|
||||
|
||||
r = s->data;
|
||||
wev = s->peer.connection->write;
|
||||
|
||||
len = sizeof("nginx client test\n") - 1;
|
||||
b = ngx_create_temp_buf(s->pool, len);
|
||||
|
||||
if (b == NULL) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
b->last = ngx_copy(b->last, "nginx client test\n", len);
|
||||
b->last_buf = 1;
|
||||
|
||||
out.buf = b;
|
||||
out.next = NULL;
|
||||
|
||||
ngx_client_write(s, &out);
|
||||
|
||||
ngx_handle_write_event(wev, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_client_test_recv(ngx_client_session_t *s)
|
||||
{
|
||||
ngx_buf_t *b;
|
||||
ngx_int_t n;
|
||||
ngx_connection_t *c;
|
||||
ngx_str_t recv;
|
||||
ngx_http_request_t *r;
|
||||
|
||||
c = s->peer.connection;
|
||||
r = s->data;
|
||||
|
||||
b = ngx_create_temp_buf(s->pool, 4096);
|
||||
if (b == NULL) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
n = c->recv(c, b->pos, b->end - b->last);
|
||||
if (n == NGX_AGAIN) {
|
||||
ngx_log_error(NGX_LOG_ERR, &s->log, 0, "client recv NGX_AGAIN");
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == NGX_ERROR || n == 0) {
|
||||
ngx_log_error(NGX_LOG_ERR, &s->log, 0, "client recv NGX_ERROR");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
ngx_client_close(s);
|
||||
return;
|
||||
}
|
||||
|
||||
b->last += n;
|
||||
|
||||
recv.data = b->pos;
|
||||
recv.len = b->last - b->pos;
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, &s->log, 0, "client recv %d: %V, %z",
|
||||
n, &recv, recv.len);
|
||||
|
||||
ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
|
||||
ngx_client_set_keepalive(s);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_client_test_send(ngx_client_session_t *s)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ERR, &s->log, 0, "client send");
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_client_test_closed(ngx_client_session_t *s)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ERR, &s->log, 0, "client closed");
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_client_test_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_client_session_t *s;
|
||||
ngx_str_t echo;
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client test handler");
|
||||
|
||||
if (ngx_http_arg(r, (u_char *) "echo", sizeof("echo") - 1, &echo)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
s = ngx_client_create(&echo, NULL, 0, r->connection->log);
|
||||
if (s == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
//ci->dynamic_resolver = 0;
|
||||
//ci->recvbuf = 4096;
|
||||
|
||||
s->client_connected = ngx_client_test_connected;
|
||||
s->client_recv = ngx_client_test_recv;
|
||||
s->client_send = ngx_client_test_send;
|
||||
s->client_closed = ngx_client_test_closed;
|
||||
s->data = r;
|
||||
|
||||
ngx_client_connect(s);
|
||||
|
||||
++r->count;
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_client_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
|
||||
clcf->handler = ngx_client_test_handler;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#include "ngx_http_client.h"
|
||||
#include "ngx_rbuf.h"
|
||||
|
||||
|
||||
static char *ngx_http_client_test(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_http_client_test_commands[] = {
|
||||
|
||||
{ ngx_string("http_client_test"),
|
||||
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
|
||||
ngx_http_client_test,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_http_client_test_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
NULL, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
NULL, /* create location configuration */
|
||||
NULL /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_http_client_test_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_client_test_module_ctx, /* module context */
|
||||
ngx_http_client_test_commands, /* module directives */
|
||||
NGX_HTTP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_client_test_recv_body(void *request, ngx_http_request_t *hcr)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_chain_t *cl = NULL;
|
||||
ngx_chain_t **ll;
|
||||
ngx_int_t rc;
|
||||
|
||||
r = request;
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"http client test recv body");
|
||||
|
||||
rc = ngx_http_client_read_body(hcr, &cl);
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"http client test recv body, rc %i %i, %O",
|
||||
rc, ngx_errno, ngx_http_client_rbytes(hcr));
|
||||
|
||||
if (rc == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
for (ll = &cl; (*ll)->next; ll = &(*ll)->next);
|
||||
|
||||
(*ll)->buf->last_buf = 1;
|
||||
}
|
||||
|
||||
ngx_http_output_filter(r, cl);
|
||||
|
||||
ngx_http_run_posted_requests(r->connection);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"all body has been read");
|
||||
ngx_http_client_finalize_request(hcr, 0);
|
||||
}
|
||||
|
||||
done:
|
||||
ngx_http_finalize_request(r, NGX_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_http_client_test_recv(void *request, ngx_http_request_t *hcr)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
static ngx_str_t content_type = ngx_string("Content-Type");
|
||||
static ngx_str_t connection = ngx_string("Connection");
|
||||
static ngx_str_t unknown = ngx_string("Unknown");
|
||||
ngx_str_t *ct, *con;
|
||||
|
||||
r = request;
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"http client test recv, connection: %p", hcr->connection);
|
||||
|
||||
r->headers_out.status = 200;
|
||||
|
||||
ngx_http_client_set_read_handler(hcr, ngx_http_client_test_recv_body);
|
||||
|
||||
ngx_http_send_header(r);
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"status_code: %ui http_version: %ui",
|
||||
ngx_http_client_status_code(hcr),
|
||||
ngx_http_client_http_version(hcr));
|
||||
|
||||
ct = ngx_http_client_header_in(hcr, &content_type);
|
||||
con = ngx_http_client_header_in(hcr, &connection);
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "Content-Type: %V", ct);
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "Connection: %V", con);
|
||||
|
||||
if (ngx_http_client_header_in(hcr, &unknown) == NULL) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "no header Unknown");
|
||||
}
|
||||
|
||||
ngx_http_client_test_recv_body(request, hcr);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_client_test_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_request_t *hcr;
|
||||
static ngx_str_t request_url = ngx_string("http://101.200.241.232/");
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"http client test handler");
|
||||
|
||||
// Default header Host, User-Agent, Connection(below HTTP/1.1), Accept, Date
|
||||
hcr = ngx_http_client_create(r->connection->log, NGX_HTTP_CLIENT_GET,
|
||||
&request_url, NULL, NULL, r);
|
||||
|
||||
// add Connection, delete Date, Modify Host, add new header
|
||||
ngx_str_t value;
|
||||
|
||||
value.data = (u_char *) "World";
|
||||
value.len = sizeof("World") - 1;
|
||||
|
||||
ngx_keyval_t headers[] = {
|
||||
{ ngx_string("Host"), ngx_string("www.test.com") },
|
||||
{ ngx_string("Connection"), ngx_string("upgrade") },
|
||||
{ ngx_string("Date"), ngx_null_string },
|
||||
{ ngx_string("Hello"), value },
|
||||
{ ngx_null_string, ngx_null_string } // must end with null str
|
||||
};
|
||||
ngx_http_client_set_headers(hcr, headers);
|
||||
|
||||
ngx_http_client_set_read_handler(hcr, ngx_http_client_test_recv);
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"http client test before send");
|
||||
|
||||
ngx_http_client_send(hcr);
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"http client test after send");
|
||||
|
||||
// ngx_http_client_detach(hcr);
|
||||
// return NGX_HTTP_FORBIDDEN;
|
||||
|
||||
++r->count;
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_client_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
|
||||
clcf->handler = ngx_http_client_test_handler;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func handleConnection(c net.Conn) {
|
||||
b := make([]byte, 4096)
|
||||
|
||||
for {
|
||||
n, err := c.Read(b)
|
||||
if err != nil {
|
||||
fmt.Print("Read Error ", err)
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Print("recv ", n, " data:", string(b))
|
||||
|
||||
c.Write(b[0:n])
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
ln, err := net.Listen("tcp", ":10000")
|
||||
if err != nil {
|
||||
fmt.Print("Listen Error ", err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
fmt.Print("Accept Error ", err)
|
||||
continue
|
||||
}
|
||||
|
||||
go handleConnection(conn)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
Copyright (C) 2016-2020, by Jie Wu "AlexWoo" <wj19840501@gmail.com>.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
# Module nginx-multiport-module
|
||||
---
|
||||
## Instructions
|
||||
|
||||
Every worker process can bind own port, user can visit specific worker process by using the port.
|
||||
|
||||
- [ngx-stream-zone-module](doc/ngx-stream-zone-module.md)
|
||||
|
||||
Record stream's owner worker process slot
|
||||
|
||||
- [ngx-http-broadcast-module](doc/ngx-http-broadcast-module.md)
|
||||
|
||||
Broadcast HTTP request to all worker processes when receive HTTP request
|
||||
|
||||
## Directives
|
||||
|
||||
### multi\_listen
|
||||
|
||||
Syntax : multi_listen multiport relationport;
|
||||
Default : None;
|
||||
Context : events
|
||||
|
||||
multiport can configured as below:
|
||||
|
||||
address:port
|
||||
port
|
||||
unix:path
|
||||
|
||||
when configured with IPv4 or IPv6 port, worker process listen port plus with worker process's slot. For Example, we start four workers, add configured multiport with 9000. worker 0 will listen 9000, worker 1 will listen 9001, worker 2 will listen 9002, worker 3 will listen 9003
|
||||
|
||||
when configured with unix path, worker will listen path plus with suffix of worker process's slot. For Example, we start four workers, add configured multiport with unix:/tmp/http. worker 0 will listen /tmp/http.0, worker 1 will listen /tmp/http.1, worker 2 will listen /tmp/http.2, worker 3 will listen /tmp/http.3
|
||||
|
||||
|
||||
relationport must configured same as listen directives in http server, rtmp server, stream server or other server
|
||||
|
||||
### inner\_proxy
|
||||
|
||||
Syntax : inner_proxy multiport uri;
|
||||
Default : None;
|
||||
Context : http, server, location
|
||||
|
||||
- multiport: configured in multi_listen
|
||||
- uri: uri for inner_proxy, configured as below
|
||||
|
||||
location /multiport_test/ {
|
||||
inner_proxy unix:/tmp/http.sock.80 /inner_proxy;
|
||||
multiport_test;
|
||||
}
|
||||
|
||||
location /inner_proxy/ {
|
||||
rewrite ^/inner_proxy/(.*):/(.*) /$2 break;
|
||||
proxy_pass http://$1:;
|
||||
}
|
||||
|
||||
As example above, if send subrequest to process whose workerid is 0, the uri will change to /inner_proxy/unix:/tmp/http.sock.80.0:/multiport_test/xxx
|
||||
|
||||
proxy_pass will send current request to process 0 as inner proxy request.
|
||||
|
||||
## API
|
||||
|
||||
- ngx\_multiport\_get\_port
|
||||
|
||||
ngx_int_t ngx_event_multiport_get_port(ngx_pool_t *pool, ngx_str_t *port, ngx_str_t *multiport, ngx_int_t pslot);
|
||||
|
||||
- para:
|
||||
|
||||
pool: pool for port memory alloc
|
||||
port: process real listen port while process\_slot is pslot
|
||||
multiport: port configure for processes, format as below:
|
||||
|
||||
port only: port
|
||||
IPv4: host:port host must be ipaddr of IPv4 or *
|
||||
IPv6: [host]:port host must be ipaddr of IPv6
|
||||
Unix: unix:/path
|
||||
|
||||
pslot: process\_slot, process\_slot of other worker process can get through ngx\_process\_slot\_get\_slot
|
||||
|
||||
- return value:
|
||||
|
||||
NGX\_OK for successd, NGX\_ERROR for failed
|
||||
|
||||
- ngx\_multiport\_get\_slot
|
||||
|
||||
ngx_int_t ngx_multiport_get_slot(ngx_uint_t wpid);
|
||||
|
||||
- para:
|
||||
|
||||
wpid: worker process id, 0 to ccf->worker_processes - 1
|
||||
|
||||
- return value:
|
||||
|
||||
ngx_process_slot for successd, NGX_ERROR for failed
|
||||
|
||||
- ngx\_http\_inner\_proxy\_request
|
||||
|
||||
ngx_int_t ngx_http_inner_proxy_request(ngx_http_request_t *r, ngx_int_t pslot);
|
||||
|
||||
send a inner proxy request to specific process, must use with directives inner\_proxy
|
||||
|
||||
- paras:
|
||||
|
||||
- r: http request for send inner request to sibling worker
|
||||
- pslot: sibling worker ngx_process_slot
|
||||
|
||||
- return values:
|
||||
|
||||
- NGX_OK: for successd
|
||||
- NGX_ERROR: for failed
|
||||
- NGX_DECLINED: for not configured or send inner proxy to self
|
||||
|
||||
## Build
|
||||
|
||||
cd to NGINX source directory & run this:
|
||||
|
||||
./configure --add-module=/path/to/nginx-multiport-module/
|
||||
make && make install
|
||||
|
||||
## Example
|
||||
|
||||
See t/ngx\_http\_process\_slot\_test\_module.c as reference
|
||||
|
||||
**Build**:
|
||||
|
||||
./configure --with-debug --with-ipv6 --add-module=/path/to/nginx-multiport-module/t/ --add-module=/path/to/nginx-multiport-module/ --add-module=/path/to/echo-nginx-module/
|
||||
|
||||
make && make install
|
||||
|
||||
**Configure**:
|
||||
|
||||
worker_processes 4;
|
||||
|
||||
events {
|
||||
...
|
||||
|
||||
multi_listen 9000 80;
|
||||
multi_listen unix:/tmp/http.sock.80 80;
|
||||
}
|
||||
|
||||
http {
|
||||
...
|
||||
|
||||
server {
|
||||
...
|
||||
|
||||
location /multiport_test/ {
|
||||
inner_proxy unix:/tmp/http.sock.80 /inner_proxy;
|
||||
multiport_test;
|
||||
}
|
||||
|
||||
location /inner_proxy/ {
|
||||
rewrite ^/inner_proxy/(.*):/(.*) /$2 break;
|
||||
proxy_pass http://$1:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
**Test for API**:
|
||||
|
||||
$ curl http://192.168.84.254/multiport_test/123
|
||||
TEST cases 19, 19 pass
|
||||
|
||||
If request send to worker1 to worker3, the request will proxy to worker 0. will get log as below:
|
||||
|
||||
2017/10/14 20:45:44 [error] 20065#0: *6 multiport test handler, client: 192.168.84.1, server: localhost, request: "GET /multiport_test/123 HTTP/1.1", host: "192.168.84.254:9003"
|
||||
2017/10/14 20:45:44 [error] 20065#0: *6 inner proxy return 0, client: 192.168.84.1, server: localhost, request: "GET /multiport_test/123 HTTP/1.1", host: "192.168.84.254:9003"
|
||||
2017/10/14 20:45:44 [error] 20062#0: *8 multiport test handler, client: unix:, server: localhost, request: "GET //multiport_test/123 HTTP/1.0", host: "localhost"
|
||||
|
||||
**Test for multiport**:
|
||||
|
||||
curl -v http://127.0.0.1/
|
||||
curl -v http://127.0.0.1:9000/
|
||||
curl -v http://127.0.0.1:9001/
|
||||
curl -v http://127.0.0.1:9002/
|
||||
curl -v http://127.0.0.1:9003/
|
||||
|
||||
curl -v --unix-socket /tmp/http.sock.80.0 http:/
|
||||
curl -v --unix-socket /tmp/http.sock.80.1 http:/
|
||||
curl -v --unix-socket /tmp/http.sock.80.2 http:/
|
||||
curl -v --unix-socket /tmp/http.sock.80.3 http:/
|
||||
|
||||
Tests will get the same result, for port 9000 will always send to worker process 0, 9001 to worker process 1 and so on
|
||||
@@ -0,0 +1,31 @@
|
||||
ngx_addon_name=ngx_multiport_module
|
||||
|
||||
EVENT_MODULES="$EVENT_MODULES \
|
||||
ngx_event_multiport_module \
|
||||
"
|
||||
|
||||
CORE_MODULES="$CORE_MODULES \
|
||||
ngx_process_slot_module \
|
||||
ngx_stream_zone_module \
|
||||
"
|
||||
|
||||
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES \
|
||||
ngx_http_broadcast_module \
|
||||
ngx_http_inner_proxy_module \
|
||||
"
|
||||
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
|
||||
$ngx_addon_dir/ngx_multiport_misc.c \
|
||||
$ngx_addon_dir/ngx_event_multiport_module.c \
|
||||
$ngx_addon_dir/ngx_process_slot_module.c \
|
||||
$ngx_addon_dir/ngx_stream_zone_module.c \
|
||||
$ngx_addon_dir/ngx_http_broadcast_module.c \
|
||||
$ngx_addon_dir/ngx_http_inner_proxy_module.c \
|
||||
"
|
||||
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
|
||||
$ngx_addon_dir/ngx_multiport.h \
|
||||
$ngx_addon_dir/ngx_stream_zone_module.h \
|
||||
"
|
||||
|
||||
CFLAGS="$CFLAGS -I $ngx_addon_dir"
|
||||
@@ -0,0 +1,77 @@
|
||||
# ngx-http-broadcast-module
|
||||
---
|
||||
## Instructions
|
||||
|
||||
Broadcast HTTP request to all worker processes when receive HTTP request
|
||||
|
||||
## Directives
|
||||
|
||||
### broadcast
|
||||
|
||||
Syntax : broadcast multiport uri;
|
||||
Default : None;
|
||||
Context : location
|
||||
|
||||
- multiport is multi_listen port configured in event
|
||||
- uri is http proxy_pass uri configured as below
|
||||
|
||||
|
||||
location /auth_proxy/ {
|
||||
rewrite ^/auth_proxy/(.*) /auth break;
|
||||
proxy_pass http://$1:;
|
||||
}
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
cd to NGINX source directory & run this:
|
||||
|
||||
./configure --add-module=/path/to/nginx-multiport-module/
|
||||
make && make install
|
||||
|
||||
## Example
|
||||
|
||||
**Build**:
|
||||
|
||||
./configure --with-debug --with-ipv6 --add-module=/path/to/nginx-multiport-module/t/ --add-module=/path/to/nginx-multiport-module/ --add-module=/path/to/echo-nginx-module/
|
||||
make && make install
|
||||
|
||||
**Configure**:
|
||||
|
||||
events {
|
||||
...
|
||||
multi_listen unix:/tmp/http.sock.80 80;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
...
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
...
|
||||
|
||||
location / {
|
||||
broadcast unix:/tmp/http.sock.80 /auth_proxy;
|
||||
}
|
||||
|
||||
location /auth_proxy/ {
|
||||
rewrite ^/auth_proxy/(.*) /auth break;
|
||||
proxy_pass http://$1:;
|
||||
}
|
||||
|
||||
location /auth {
|
||||
# return 403;
|
||||
echo "auth";
|
||||
echo $scheme://$host$uri?$args;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
**Test**:
|
||||
|
||||
curl -v 'http://192.168.84.254/aa?a=b&c=d'
|
||||
|
||||
curl will get all response content if worker not return non 200 response
|
||||
@@ -0,0 +1,92 @@
|
||||
# ngx-stream-zone-module
|
||||
---
|
||||
## Instructions
|
||||
|
||||
Record stream's owner worker process slot
|
||||
|
||||
## Directives
|
||||
|
||||
### stream\_zone
|
||||
|
||||
Syntax : stream_zone buckets=$nbuckets streams=$nstreams;
|
||||
Default : None;
|
||||
Context : main
|
||||
|
||||
nbuckets is hash buckect number, nstreams is max streams system can store
|
||||
|
||||
nbuckets is recommended use a prime number
|
||||
|
||||
## API
|
||||
|
||||
**header file**
|
||||
|
||||
For using this API, You should include the header file as below:
|
||||
|
||||
#include "ngx_stream_zone_module.h"
|
||||
|
||||
**ngx\_stream\_zone\_insert\_stream**
|
||||
|
||||
ngx_int_t ngx_stream_zone_insert_stream(ngx_str_t *name);
|
||||
|
||||
- para:
|
||||
|
||||
name: stream name
|
||||
|
||||
- return value:
|
||||
|
||||
process\_slot for owner of stream, NGX\_ERROR for error
|
||||
|
||||
**ngx\_stream\_zone\_delete\_stream**
|
||||
|
||||
void ngx_stream_zone_delete_stream(ngx_str_t *name);
|
||||
|
||||
- para:
|
||||
|
||||
name: stream name
|
||||
|
||||
**ngx\_stream\_zone\_state**
|
||||
|
||||
ngx_chain_t *ngx_stream_zone_state(ngx_http_request_t *r, ngx_flag_t detail);
|
||||
|
||||
- para:
|
||||
|
||||
- r: http request to query status of rbuf
|
||||
- detail: print stream detail in log
|
||||
|
||||
- return value:
|
||||
|
||||
chain of stream zone state for returning to http client
|
||||
|
||||
## Build
|
||||
|
||||
cd to NGINX source directory & run this:
|
||||
|
||||
./configure --add-module=/path/to/nginx-multiport-module/
|
||||
make && make install
|
||||
|
||||
## Example
|
||||
|
||||
See t/ngx\_stream\_zone\_test\_module.c as reference
|
||||
|
||||
**Build**:
|
||||
|
||||
./configure --with-debug --with-ipv6 --add-module=/path/to/nginx-multiport-module/t/ --add-module=/path/to/nginx-multiport-module/
|
||||
make && make install
|
||||
|
||||
**Configure**:
|
||||
|
||||
stream_zone buckets=10007 streams=10000;
|
||||
|
||||
**Test**:
|
||||
|
||||
curl -XPOST -v "http://127.0.0.1:9001/stream_zone_test/ab?stream=test"
|
||||
curl -XPOST -v "http://127.0.0.1:9002/stream_zone_test/ab?stream=test1"
|
||||
curl -XPOST -v "http://127.0.0.1:9003/stream_zone_test/ab?stream=test2"
|
||||
|
||||
curl -XPOST -v "http://127.0.0.1:9003/stream_zone_test/ab?stream=test"
|
||||
|
||||
curl -XDELETE -v "http://127.0.0.1:9000/stream_zone_test/ab?stream=test3"
|
||||
curl -XDELETE -v "http://127.0.0.1:9002/stream_zone_test/ab?stream=test1"
|
||||
curl -XDELETE -v "http://127.0.0.1:9001/stream_zone_test/ab?stream=test2"
|
||||
|
||||
curl -XGET -v "http://127.0.0.1:9001/stream_zone_test/ab"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include "ngx_multiport.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t multiport;
|
||||
ngx_str_t uri;
|
||||
} ngx_http_broadcast_conf_t;
|
||||
|
||||
typedef struct {
|
||||
ngx_int_t workerid;
|
||||
ngx_http_request_t *sr;
|
||||
} ngx_http_broadcast_ctx_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_broadcast_filter_init(ngx_conf_t *cf);
|
||||
|
||||
static void *ngx_http_broadcast_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_broadcast_merge_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static char *ngx_http_broadcast(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_http_broadcast_commands[] = {
|
||||
|
||||
{ ngx_string("broadcast"),
|
||||
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
|
||||
ngx_http_broadcast,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_http_broadcast_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_http_broadcast_filter_init, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
ngx_http_broadcast_create_conf, /* create location configuration */
|
||||
ngx_http_broadcast_merge_conf /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_http_broadcast_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_broadcast_module_ctx, /* module context */
|
||||
ngx_http_broadcast_commands, /* module directives */
|
||||
NGX_HTTP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
|
||||
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
|
||||
|
||||
|
||||
static void *
|
||||
ngx_http_broadcast_create_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_broadcast_conf_t *conf;
|
||||
|
||||
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_broadcast_conf_t));
|
||||
if (conf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_http_broadcast_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_http_broadcast_conf_t *prev = parent;
|
||||
ngx_http_broadcast_conf_t *conf = child;
|
||||
|
||||
ngx_conf_merge_str_value(conf->multiport, prev->multiport, "");
|
||||
ngx_conf_merge_str_value(conf->uri, prev->uri, "");
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_http_broadcast(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_broadcast_conf_t *hbcf;
|
||||
ngx_str_t *value;
|
||||
|
||||
hbcf = conf;
|
||||
|
||||
if (hbcf->multiport.data != NULL) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
hbcf->multiport = value[1];
|
||||
hbcf->uri = value[2];
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_broadcast_header_filter(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_broadcast_conf_t *hbcf;
|
||||
|
||||
hbcf = ngx_http_get_module_loc_conf(r, ngx_http_broadcast_module);
|
||||
|
||||
if (hbcf == NULL || hbcf->multiport.len == 0) { /* not configured */
|
||||
goto next;
|
||||
}
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"broadcast header filter, r:%p r->main:%p, %ui, %O",
|
||||
r, r->main, r->headers_out.status, r->headers_out.content_length_n);
|
||||
|
||||
r->headers_out.status = NGX_HTTP_OK;
|
||||
ngx_http_clear_content_length(r);
|
||||
ngx_http_clear_accept_ranges(r);
|
||||
|
||||
next:
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_broadcast_send_subrequest(ngx_http_request_t *r, ngx_int_t pslot)
|
||||
{
|
||||
ngx_http_broadcast_conf_t *hbcf;
|
||||
ngx_str_t uri;
|
||||
ngx_str_t port;
|
||||
ngx_http_request_t *sr;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"broadcast send subrequest to %i", pslot);
|
||||
|
||||
hbcf = ngx_http_get_module_loc_conf(r, ngx_http_broadcast_module);
|
||||
|
||||
if (ngx_multiport_get_port(r->pool, &port, &hbcf->multiport, pslot)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"broadcast get port error, %V %i", &hbcf->multiport, pslot);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
uri.len = hbcf->uri.len + 1 + port.len;
|
||||
uri.data = ngx_pcalloc(r->pool, uri.len);
|
||||
ngx_snprintf(uri.data, uri.len, "%V/%V", &hbcf->uri, &port);
|
||||
|
||||
rc = ngx_http_subrequest(r, &uri, &r->args, &sr, NULL, 0);
|
||||
sr->method = r->method;
|
||||
sr->method_name = r->method_name;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_broadcast_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
ngx_http_broadcast_conf_t *hbcf;
|
||||
ngx_http_broadcast_ctx_t *ctx;
|
||||
ngx_core_conf_t *ccf;
|
||||
ngx_int_t rc;
|
||||
ngx_buf_t *b;
|
||||
ngx_chain_t cl;
|
||||
|
||||
hbcf = ngx_http_get_module_loc_conf(r->main, ngx_http_broadcast_module);
|
||||
|
||||
if (hbcf == NULL || hbcf->multiport.len == 0) { /* not configured */
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"broadcast body filter, r:%p r->main:%p", r, r->main);
|
||||
|
||||
if (r != r->main) { /* send subrequest */
|
||||
if (r->headers_out.status != NGX_HTTP_OK) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"broadcast subrequest send non 200 response: %i",
|
||||
r->headers_out.status);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_broadcast_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_broadcast_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_set_ctx(r, ctx, ngx_http_broadcast_module);
|
||||
}
|
||||
|
||||
/* send to all process */
|
||||
|
||||
ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_core_module);
|
||||
|
||||
while (ctx->workerid < ccf->worker_processes) {
|
||||
|
||||
rc = ngx_http_broadcast_send_subrequest(r,
|
||||
ngx_multiport_get_slot(ctx->workerid));
|
||||
++ctx->workerid;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
|
||||
|
||||
if (b == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
b->last_buf = 1;
|
||||
|
||||
cl.buf = b;
|
||||
cl.next = NULL;
|
||||
|
||||
return ngx_http_next_body_filter(r, &cl);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_broadcast_filter_init(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_next_header_filter = ngx_http_top_header_filter;
|
||||
ngx_http_top_header_filter = ngx_http_broadcast_header_filter;
|
||||
|
||||
ngx_http_next_body_filter = ngx_http_top_body_filter;
|
||||
ngx_http_top_body_filter = ngx_http_broadcast_body_filter;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include "ngx_multiport.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t multiport;
|
||||
ngx_str_t uri;
|
||||
} ngx_http_inner_proxy_conf_t;
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t port;
|
||||
ngx_flag_t last;
|
||||
} ngx_http_inner_proxy_ctx_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_inner_proxy_filter_init(ngx_conf_t *cf);
|
||||
|
||||
static void *ngx_http_inner_proxy_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_inner_proxy_merge_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
static char *ngx_http_inner_proxy(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_http_inner_proxy_commands[] = {
|
||||
|
||||
{ ngx_string("inner_proxy"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
|
||||
ngx_http_inner_proxy,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_http_inner_proxy_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_http_inner_proxy_filter_init, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
ngx_http_inner_proxy_create_conf, /* create location configuration */
|
||||
ngx_http_inner_proxy_merge_conf /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_http_inner_proxy_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_inner_proxy_module_ctx, /* module context */
|
||||
ngx_http_inner_proxy_commands, /* module directives */
|
||||
NGX_HTTP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
|
||||
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
|
||||
|
||||
|
||||
static void *
|
||||
ngx_http_inner_proxy_create_conf(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_inner_proxy_conf_t *conf;
|
||||
|
||||
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_inner_proxy_conf_t));
|
||||
if (conf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_http_inner_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
{
|
||||
ngx_http_inner_proxy_conf_t *prev = parent;
|
||||
ngx_http_inner_proxy_conf_t *conf = child;
|
||||
|
||||
ngx_conf_merge_str_value(conf->multiport, prev->multiport, "");
|
||||
ngx_conf_merge_str_value(conf->uri, prev->uri, "");
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_http_inner_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_inner_proxy_conf_t *hipcf;
|
||||
ngx_str_t *value;
|
||||
|
||||
hipcf = conf;
|
||||
|
||||
if (hipcf->multiport.data != NULL) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
hipcf->multiport = value[1];
|
||||
hipcf->uri = value[2];
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_inner_proxy_header_filter(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_inner_proxy_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r->main, ngx_http_inner_proxy_module);
|
||||
|
||||
if (ctx == NULL) { /* not configured */
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
if (r == r->main) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
r->main->headers_out = r->headers_out;
|
||||
|
||||
return ngx_http_next_header_filter(r->main);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_inner_proxy_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
ngx_http_inner_proxy_ctx_t *ctx;
|
||||
ngx_chain_t *cl, l;
|
||||
ngx_buf_t *b;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r->main, ngx_http_inner_proxy_module);
|
||||
|
||||
if (ctx == NULL) { /* not configured */
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
if (r == r->main) {
|
||||
if (ctx->last == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
|
||||
|
||||
if (b == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
b->last_buf = 1;
|
||||
|
||||
l.buf = b;
|
||||
l.next = NULL;
|
||||
|
||||
return ngx_http_next_body_filter(r, &l);
|
||||
}
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
if (cl->buf->last_in_chain) {
|
||||
ctx->last = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_inner_proxy_filter_init(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_next_header_filter = ngx_http_top_header_filter;
|
||||
ngx_http_top_header_filter = ngx_http_inner_proxy_header_filter;
|
||||
|
||||
ngx_http_next_body_filter = ngx_http_top_body_filter;
|
||||
ngx_http_top_body_filter = ngx_http_inner_proxy_body_filter;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_inner_proxy_request(ngx_http_request_t *r, ngx_int_t pslot)
|
||||
{
|
||||
ngx_http_inner_proxy_conf_t *hipcf;
|
||||
ngx_http_inner_proxy_ctx_t *ctx;
|
||||
ngx_http_request_t *sr;
|
||||
ngx_str_t uri;
|
||||
ngx_int_t rc;
|
||||
|
||||
hipcf = ngx_http_get_module_loc_conf(r, ngx_http_inner_proxy_module);
|
||||
|
||||
if (hipcf == NULL || hipcf->multiport.len == 0) { /* not configured */
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (pslot == ngx_process_slot) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"inner proxy send request to self: %i", ngx_process_slot);
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_inner_proxy_module);
|
||||
if (ctx) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"inner proxy has been called in this request");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_inner_proxy_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
ngx_http_set_ctx(r, ctx, ngx_http_inner_proxy_module);
|
||||
|
||||
if (ngx_multiport_get_port(r->pool, &ctx->port, &hipcf->multiport, pslot)
|
||||
== NGX_ERROR)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
uri.len = hipcf->uri.len + 1 + ctx->port.len + 2 + r->uri.len;
|
||||
uri.data = ngx_pcalloc(r->pool, uri.len);
|
||||
ngx_snprintf(uri.data, uri.len, "%V/%V:/%V",
|
||||
&hipcf->uri, &ctx->port, &r->uri);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"inner proxy send request to %V", &ctx->port);
|
||||
rc = ngx_http_subrequest(r, &uri, &r->args, &sr, NULL, 0);
|
||||
sr->method = r->method;
|
||||
sr->method_name = r->method_name;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_MULTIPORT_H_INCLUDED_
|
||||
#define _NGX_MULTIPORT_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
/*
|
||||
* return value:
|
||||
* NGX_OK for success, NGX_ERROR for failed
|
||||
* paras:
|
||||
* pool: pool for port memory alloc
|
||||
* port: process real listen port while process_slot is pslot
|
||||
* multiport: port configure for processes, format as below:
|
||||
* port only: port
|
||||
* IPv4: host:port host must be ipaddr of IPv4 or *
|
||||
* IPv6: [host]:port host must be ipaddr of IPv6
|
||||
* Unix: unix:/path
|
||||
* pslot: process_slot
|
||||
*/
|
||||
ngx_int_t ngx_multiport_get_port(ngx_pool_t *pool, ngx_str_t *port,
|
||||
ngx_str_t *multiport, ngx_int_t pslot);
|
||||
|
||||
|
||||
/*
|
||||
* return value:
|
||||
* ngx_process_slot for successd, NGX_ERROR for failed
|
||||
* paras:
|
||||
* wpid: worker process id, 0 to ccf->worker_processes - 1
|
||||
*/
|
||||
ngx_int_t ngx_multiport_get_slot(ngx_uint_t wpid);
|
||||
|
||||
|
||||
/*
|
||||
* return value:
|
||||
* NGX_OK : for successd
|
||||
* NGX_ERROR : for failed
|
||||
* NGX_DECLINED: for not configured or send inner proxy to self
|
||||
* paras:
|
||||
* r : http request for send inner request to sibling worker
|
||||
* pslot: sibling worker ngx_process_slot
|
||||
*/
|
||||
ngx_int_t ngx_http_inner_proxy_request(ngx_http_request_t *r, ngx_int_t pslot);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,165 @@
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_multiport_get_port_unix(ngx_pool_t *pool, ngx_str_t *port,
|
||||
ngx_str_t *multiport, ngx_int_t pslot)
|
||||
{
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
u_char *p;
|
||||
size_t len;
|
||||
|
||||
len = multiport->len + 5; /* unix:/path -> unix:/path.127\0 */
|
||||
port->data = ngx_pcalloc(pool, len);
|
||||
if (port->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_snprintf(port->data, len, "%V.%i", multiport, pslot);
|
||||
*p = 0;
|
||||
port->len = p - port->data;
|
||||
|
||||
return NGX_OK;
|
||||
#else
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"the unix domain sockets not support");
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_multiport_get_port_inet6(ngx_pool_t *pool, ngx_str_t *port,
|
||||
ngx_str_t *multiport, ngx_int_t pslot)
|
||||
{
|
||||
#if (NGX_HAVE_INET6)
|
||||
u_char *p, *last;
|
||||
ngx_str_t addr;
|
||||
size_t len;
|
||||
ngx_int_t n;
|
||||
|
||||
last = multiport->data + multiport->len;
|
||||
p = ngx_strlchr(multiport->data, last, ']');
|
||||
|
||||
if (p == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "invalid INET6 host");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
++p;
|
||||
if (p == last || *p != ':') {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no INET6 port");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
++p;
|
||||
addr.data = multiport->data;
|
||||
addr.len = p - multiport->data;
|
||||
|
||||
len = last - p;
|
||||
n = ngx_atoi(p, len);
|
||||
|
||||
/* 65408 + 127 = 65535, pslot in [0, 127] */
|
||||
if (n < 1 || n + pslot > 65408) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "invalid INET6 port");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
n += pslot;
|
||||
|
||||
len = multiport->len + 3; /* [::]:1 -> [::]:128\0 */
|
||||
port->data = ngx_pcalloc(pool, len);
|
||||
if (port->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = port->data;
|
||||
p = ngx_snprintf(p, len, "%V%i", &addr, n);
|
||||
port->len = p - port->data;
|
||||
|
||||
return NGX_OK;
|
||||
#else
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"the INET6 sockets not support");
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_multiport_get_port_inet(ngx_pool_t *pool, ngx_str_t *port,
|
||||
ngx_str_t *multiport, ngx_int_t pslot)
|
||||
{
|
||||
u_char *p, *last;
|
||||
ngx_str_t addr;
|
||||
size_t len;
|
||||
ngx_int_t n;
|
||||
|
||||
last = multiport->data + multiport->len;
|
||||
p = ngx_strlchr(multiport->data, last, ':');
|
||||
|
||||
if (p == NULL) { /* port */
|
||||
p = multiport->data;
|
||||
addr.len = 0;
|
||||
} else { /* host:port */
|
||||
++p;
|
||||
if (p == last) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no port");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
addr.data = multiport->data;
|
||||
addr.len = p - multiport->data;
|
||||
}
|
||||
|
||||
len = last - p;
|
||||
n = ngx_atoi(p, len);
|
||||
|
||||
/* 65408 + 127 = 65535, pslot in [0, 127] */
|
||||
if (n < 1 || n + pslot > 65408) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "invalid port");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
n += pslot;
|
||||
|
||||
len = multiport->len + 3; /* 127.0.0.1:1 -> 127.0.0.1:128\0 */
|
||||
port->data = ngx_pcalloc(pool, len);
|
||||
if (port->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = port->data;
|
||||
if (addr.len == 0) {
|
||||
p = ngx_snprintf(p, len, "%i", n);
|
||||
} else {
|
||||
p = ngx_snprintf(p, len, "%V%i", &addr, n);
|
||||
}
|
||||
port->len = p - port->data;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_int_t
|
||||
ngx_multiport_get_port(ngx_pool_t *pool, ngx_str_t *port,
|
||||
ngx_str_t *multiport, ngx_int_t pslot)
|
||||
{
|
||||
u_char *p;
|
||||
size_t len;
|
||||
|
||||
p = multiport->data;
|
||||
len = multiport->len;
|
||||
|
||||
if (pslot < 0 || pslot > 127) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "invalid pslot: %i",
|
||||
pslot);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
|
||||
return ngx_multiport_get_port_unix(pool, port, multiport, pslot);
|
||||
}
|
||||
|
||||
if (len && p[0] == '[') {
|
||||
return ngx_multiport_get_port_inet6(pool, port, multiport, pslot);
|
||||
}
|
||||
|
||||
return ngx_multiport_get_port_inet(pool, port, multiport, pslot);
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_process_slot_module_init(ngx_cycle_t *cycle);
|
||||
static ngx_int_t ngx_process_slot_process_init(ngx_cycle_t *cycle);
|
||||
static void ngx_process_slot_process_exit(ngx_cycle_t *cycle);
|
||||
|
||||
static void *ngx_process_slot_module_create_conf(ngx_cycle_t *cycle);
|
||||
static char *ngx_process_slot_module_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
|
||||
|
||||
#define MAX_PROCESSES 128
|
||||
|
||||
typedef struct {
|
||||
ngx_atomic_int_t process_slot[MAX_PROCESSES];
|
||||
} ngx_process_slot_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
ngx_process_slot_ctx_t *ctx;
|
||||
} ngx_process_slot_conf_t;
|
||||
|
||||
|
||||
static ngx_command_t ngx_process_slot_commands[] = {
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_core_module_t ngx_process_slot_module_ctx = {
|
||||
ngx_string("process_slot"),
|
||||
ngx_process_slot_module_create_conf,
|
||||
ngx_process_slot_module_init_conf
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_process_slot_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_process_slot_module_ctx, /* module context */
|
||||
ngx_process_slot_commands, /* module directives */
|
||||
NGX_CORE_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
ngx_process_slot_module_init, /* init module */
|
||||
ngx_process_slot_process_init, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
ngx_process_slot_process_exit, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static void *
|
||||
ngx_process_slot_module_create_conf(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_process_slot_conf_t *pscf;
|
||||
|
||||
pscf = ngx_palloc(cycle->pool, sizeof(ngx_process_slot_conf_t));
|
||||
if (pscf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pscf;
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_process_slot_module_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_process_slot_module_init(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_process_slot_conf_t *pscf;
|
||||
ngx_shm_t shm;
|
||||
ngx_uint_t i;
|
||||
|
||||
pscf = (ngx_process_slot_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_process_slot_module);
|
||||
|
||||
shm.size = sizeof(ngx_process_slot_ctx_t);
|
||||
shm.name.len = sizeof("process_slot_zone") - 1;
|
||||
shm.name.data = (u_char *) "process_slot_zone";
|
||||
shm.log = cycle->log;
|
||||
|
||||
if (ngx_shm_alloc(&shm) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pscf->ctx = (ngx_process_slot_ctx_t *) shm.addr;
|
||||
|
||||
for (i = 0; i < MAX_PROCESSES; ++i) {
|
||||
pscf->ctx->process_slot[i] = -1;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_process_slot_process_init(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_process_slot_conf_t *pscf;
|
||||
ngx_process_slot_ctx_t *ctx;
|
||||
|
||||
if (ngx_process != NGX_PROCESS_WORKER) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
pscf = (ngx_process_slot_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_process_slot_module);
|
||||
ctx = pscf->ctx;
|
||||
|
||||
for (;;) {
|
||||
if (ngx_atomic_cmp_set((ngx_atomic_t *) &ctx->process_slot[ngx_worker],
|
||||
(ngx_atomic_uint_t)ctx->process_slot[ngx_worker], ngx_process_slot))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_process_slot_process_exit(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_process_slot_conf_t *pscf;
|
||||
ngx_process_slot_ctx_t *ctx;
|
||||
|
||||
if (ngx_process != NGX_PROCESS_WORKER) {
|
||||
return;
|
||||
}
|
||||
|
||||
pscf = (ngx_process_slot_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_process_slot_module);
|
||||
ctx = pscf->ctx;
|
||||
|
||||
ngx_atomic_cmp_set((ngx_atomic_t *) &ctx->process_slot[ngx_worker],
|
||||
(ngx_atomic_uint_t)ngx_process_slot, -1);
|
||||
}
|
||||
|
||||
ngx_int_t
|
||||
ngx_multiport_get_slot(ngx_uint_t wpid)
|
||||
{
|
||||
ngx_process_slot_conf_t *pscf;
|
||||
ngx_process_slot_ctx_t *ctx;
|
||||
ngx_core_conf_t *ccf;
|
||||
|
||||
ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_core_module);
|
||||
|
||||
if (wpid >= (ngx_uint_t)ccf->worker_processes) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pscf = (ngx_process_slot_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_process_slot_module);
|
||||
ctx = pscf->ctx;
|
||||
|
||||
return ctx->process_slot[wpid];
|
||||
}
|
||||
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
typedef struct ngx_stream_zone_hash_s ngx_stream_zone_hash_t;
|
||||
typedef struct ngx_stream_zone_node_s ngx_stream_zone_node_t;
|
||||
typedef struct ngx_stream_zone_conf_s ngx_stream_zone_conf_t;
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_zone_init_process(ngx_cycle_t *cycle);
|
||||
static void
|
||||
ngx_stream_zone_exit_process(ngx_cycle_t *cycle);
|
||||
static void *
|
||||
ngx_stream_zone_create_conf(ngx_cycle_t *cf);
|
||||
static char *
|
||||
ngx_stream_zone_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||
static char *
|
||||
ngx_stream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
static char *
|
||||
ngx_stream_zone_shm_init(ngx_shm_t *shm, ngx_stream_zone_conf_t *szcf,
|
||||
ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
#define NAME_LEN 1024
|
||||
|
||||
static ngx_str_t stream_zone_key = ngx_string("stream_zone");
|
||||
|
||||
struct ngx_stream_zone_node_s {
|
||||
u_char name[NAME_LEN];
|
||||
ngx_int_t slot; /* process slot */
|
||||
ngx_int_t idx;
|
||||
ngx_int_t next; /* idx of stream node */
|
||||
};
|
||||
|
||||
struct ngx_stream_zone_hash_s {
|
||||
ngx_shmtx_t mutex;
|
||||
ngx_shmtx_sh_t lock;
|
||||
ngx_int_t node; /* idx of stream node */
|
||||
};
|
||||
|
||||
struct ngx_stream_zone_conf_s {
|
||||
ngx_int_t nbuckets;
|
||||
ngx_int_t nstreams;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
|
||||
ngx_shmtx_t *mutex;
|
||||
ngx_shmtx_sh_t *lock;
|
||||
ngx_stream_zone_hash_t *hash; /* hash in shm */
|
||||
ngx_stream_zone_node_t *stream_node;/* node in shm */
|
||||
ngx_int_t *free_node; /* free node chain */
|
||||
ngx_int_t *alloc; /* node number in use*/
|
||||
};
|
||||
|
||||
|
||||
static ngx_command_t ngx_stream_zone_commands[] = {
|
||||
|
||||
{ ngx_string("stream_zone"),
|
||||
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE2,
|
||||
ngx_stream_zone,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_core_module_t ngx_stream_zone_module_ctx = {
|
||||
ngx_string("rtmp_stream_zone"),
|
||||
ngx_stream_zone_create_conf, /* create conf */
|
||||
ngx_stream_zone_init_conf /* init conf */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_stream_zone_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_stream_zone_module_ctx, /* module context */
|
||||
ngx_stream_zone_commands, /* module directives */
|
||||
NGX_CORE_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
ngx_stream_zone_init_process, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
ngx_stream_zone_exit_process, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_stream_zone_node_t *
|
||||
ngx_stream_zone_get_node(ngx_str_t *name, ngx_int_t pslot)
|
||||
{
|
||||
ngx_stream_zone_conf_t *szcf;
|
||||
ngx_stream_zone_node_t *node;
|
||||
|
||||
szcf = (ngx_stream_zone_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_stream_zone_module);
|
||||
|
||||
ngx_shmtx_lock(szcf->mutex);
|
||||
|
||||
if (*szcf->free_node == -1) {
|
||||
ngx_shmtx_unlock(szcf->mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = &szcf->stream_node[*szcf->free_node];
|
||||
*szcf->free_node = node->next;
|
||||
|
||||
*ngx_copy(node->name, name->data, ngx_min(NAME_LEN - 1, name->len)) = '\0';
|
||||
node->slot = pslot;
|
||||
node->next = -1;
|
||||
|
||||
++*szcf->alloc;
|
||||
|
||||
ngx_shmtx_unlock(szcf->mutex);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_stream_zone_put_node(ngx_int_t idx)
|
||||
{
|
||||
ngx_stream_zone_conf_t *szcf;
|
||||
ngx_stream_zone_node_t *node;
|
||||
|
||||
szcf = (ngx_stream_zone_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_stream_zone_module);
|
||||
|
||||
ngx_shmtx_lock(szcf->mutex);
|
||||
|
||||
node = &szcf->stream_node[idx];
|
||||
|
||||
node->next = *szcf->free_node;
|
||||
*szcf->free_node = idx;
|
||||
|
||||
--*szcf->alloc;
|
||||
|
||||
ngx_shmtx_unlock(szcf->mutex);
|
||||
}
|
||||
|
||||
static void *
|
||||
ngx_stream_zone_create_conf(ngx_cycle_t *cf)
|
||||
{
|
||||
ngx_stream_zone_conf_t *conf;
|
||||
|
||||
conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_zone_conf_t));
|
||||
if (conf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conf->nbuckets = NGX_CONF_UNSET;
|
||||
conf->nstreams = NGX_CONF_UNSET;
|
||||
conf->pool = ngx_create_pool(4096, cf->log);
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_stream_zone_init_conf(ngx_cycle_t *cycle, void *conf)
|
||||
{
|
||||
size_t len;
|
||||
ngx_shm_t shm;
|
||||
ngx_stream_zone_conf_t *szcf = conf;
|
||||
|
||||
ngx_conf_init_value(szcf->nbuckets, 512);
|
||||
ngx_conf_init_value(szcf->nstreams, 40960);
|
||||
|
||||
/* create shm zone */
|
||||
len = sizeof(ngx_shmtx_t) + sizeof(ngx_shmtx_sh_t)
|
||||
+ sizeof(ngx_stream_zone_hash_t) * szcf->nbuckets
|
||||
+ sizeof(ngx_stream_zone_node_t) * szcf->nstreams
|
||||
+ sizeof(ngx_int_t) + sizeof(ngx_int_t);
|
||||
|
||||
shm.size = len;
|
||||
shm.name = stream_zone_key;
|
||||
shm.log = cycle->log;
|
||||
|
||||
if (ngx_shm_alloc(&shm) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return ngx_stream_zone_shm_init(&shm, szcf, cycle);
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_stream_zone_clear(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_stream_zone_conf_t *szcf;
|
||||
volatile ngx_int_t idx, cur, next;
|
||||
|
||||
szcf = (ngx_stream_zone_conf_t *) ngx_get_conf(cycle->conf_ctx,
|
||||
ngx_stream_zone_module);
|
||||
|
||||
if (szcf->nbuckets <= 0 || szcf->nstreams <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (idx = 0; idx < szcf->nbuckets; ++idx) {
|
||||
|
||||
ngx_shmtx_lock(&szcf->hash[idx].mutex);
|
||||
cur = -1;
|
||||
|
||||
while (1) {
|
||||
if (cur == -1) {
|
||||
next = szcf->hash[idx].node;
|
||||
} else {
|
||||
next = szcf->stream_node[cur].next;
|
||||
}
|
||||
|
||||
if (next == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (szcf->stream_node[next].slot == ngx_process_slot) {
|
||||
if (cur == -1) {
|
||||
szcf->hash[idx].node = szcf->stream_node[next].next;
|
||||
} else {
|
||||
szcf->stream_node[cur].next = szcf->stream_node[next].next;
|
||||
}
|
||||
|
||||
ngx_stream_zone_put_node(next);
|
||||
continue;
|
||||
}
|
||||
|
||||
cur = next;
|
||||
}
|
||||
ngx_shmtx_unlock(&szcf->hash[idx].mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_zone_init_process(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_stream_zone_clear(cycle);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
ngx_stream_zone_exit_process(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_stream_zone_clear(cycle);
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_stream_zone_shm_init(ngx_shm_t *shm, ngx_stream_zone_conf_t *szcf,
|
||||
ngx_cycle_t *cycle)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_int_t i, next;
|
||||
|
||||
p = shm->addr;
|
||||
|
||||
szcf->mutex = (ngx_shmtx_t *) p;
|
||||
p += sizeof(ngx_shmtx_t);
|
||||
|
||||
szcf->lock = (ngx_shmtx_sh_t *) p;
|
||||
p += sizeof(ngx_shmtx_sh_t);
|
||||
|
||||
szcf->hash = (ngx_stream_zone_hash_t *) p;
|
||||
p += sizeof(ngx_stream_zone_hash_t) * szcf->nbuckets;
|
||||
|
||||
szcf->stream_node = (ngx_stream_zone_node_t *) p;
|
||||
p += sizeof(ngx_stream_zone_node_t) * szcf->nstreams;
|
||||
|
||||
szcf->free_node = (ngx_int_t *) p;
|
||||
p += sizeof(ngx_int_t);
|
||||
|
||||
szcf->alloc = (ngx_int_t *) p;
|
||||
|
||||
/* init shm zone */
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
|
||||
p = NULL;
|
||||
|
||||
#else
|
||||
p = ngx_pnalloc(szcf->pool, cycle->lock_file.len
|
||||
+ stream_zone_key.len);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
*ngx_sprintf(p, "%V%V", &cycle->lock_file, &stream_zone_key) = 0;
|
||||
|
||||
#endif
|
||||
|
||||
if (ngx_shmtx_create(szcf->mutex, szcf->lock, p) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < szcf->nbuckets; ++i) {
|
||||
#if (NGX_HAVE_ATOMIC_OPS)
|
||||
|
||||
p = NULL;
|
||||
|
||||
#else
|
||||
p = ngx_pnalloc(szcf->pool, cycle->lock_file.len + stream_zone_key.len
|
||||
+ NGX_INT32_LEN);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
*ngx_sprintf(p, "%V%V%d", &cycle->lock_file,
|
||||
&stream_zone_key, i) = 0;
|
||||
|
||||
#endif
|
||||
|
||||
if (ngx_shmtx_create(&szcf->hash[i].mutex, &szcf->hash[i].lock, p)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
szcf->hash[i].node = -1;
|
||||
}
|
||||
|
||||
next = -1;
|
||||
i = szcf->nstreams;
|
||||
|
||||
do {
|
||||
--i;
|
||||
|
||||
szcf->stream_node[i].slot = -1;
|
||||
szcf->stream_node[i].idx = i;
|
||||
szcf->stream_node[i].next = next;
|
||||
next = i;
|
||||
} while (i);
|
||||
|
||||
*szcf->free_node = i;
|
||||
*szcf->alloc = 0;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_stream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_str_t *value;
|
||||
ngx_stream_zone_conf_t *szcf = conf;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
for (i = 1; i < cf->args->nelts; ++i) {
|
||||
|
||||
if (ngx_strncmp(value[i].data, "buckets=", 8) == 0) {
|
||||
szcf->nbuckets = ngx_atoi(value[i].data + 8, value[i].len - 8);
|
||||
|
||||
if (szcf->nbuckets <= 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid buckets \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strncmp(value[i].data, "streams=", 8) == 0) {
|
||||
szcf->nstreams = ngx_atoi(value[i].data + 8, value[i].len - 8);
|
||||
|
||||
if (szcf->nstreams <= 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid streams \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid parameter \"%V\"", &value[i]);
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_zone_insert_stream(ngx_str_t *name)
|
||||
{
|
||||
ngx_stream_zone_conf_t *szcf;
|
||||
volatile ngx_uint_t idx;
|
||||
volatile ngx_int_t i, pslot;
|
||||
ngx_stream_zone_node_t *node;
|
||||
|
||||
szcf = (ngx_stream_zone_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_stream_zone_module);
|
||||
|
||||
if (szcf->nbuckets <= 0 || szcf->nstreams <= 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (name->len >= NAME_LEN) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"stream name(%V) too long", name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
idx = ngx_hash_key(name->data, name->len) % szcf->nbuckets;
|
||||
|
||||
ngx_shmtx_lock(&szcf->hash[idx].mutex);
|
||||
i = szcf->hash[idx].node;
|
||||
pslot = -1;
|
||||
while (i != -1) {
|
||||
if (ngx_strlen(szcf->stream_node[i].name) == name->len
|
||||
&& ngx_memcmp(szcf->stream_node[i].name, name->data, name->len)
|
||||
== 0)
|
||||
{
|
||||
pslot = szcf->stream_node[i].slot;
|
||||
break;
|
||||
}
|
||||
|
||||
i = szcf->stream_node[i].next;
|
||||
}
|
||||
|
||||
if (i == -1) { /* stream not in hash */
|
||||
node = ngx_stream_zone_get_node(name, ngx_process_slot);
|
||||
if (node == NULL) {
|
||||
ngx_shmtx_unlock(&szcf->hash[idx].mutex);
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"stream zone get node failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
node->slot = ngx_process_slot;
|
||||
|
||||
node->next = szcf->hash[idx].node;
|
||||
szcf->hash[idx].node = node->idx;
|
||||
|
||||
pslot = ngx_process_slot;
|
||||
}
|
||||
ngx_shmtx_unlock(&szcf->hash[idx].mutex);
|
||||
|
||||
return pslot;
|
||||
}
|
||||
|
||||
void
|
||||
ngx_stream_zone_delete_stream(ngx_str_t *name)
|
||||
{
|
||||
ngx_stream_zone_conf_t *szcf;
|
||||
volatile ngx_uint_t idx;
|
||||
volatile ngx_int_t cur, next;
|
||||
|
||||
szcf = (ngx_stream_zone_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_stream_zone_module);
|
||||
|
||||
if (szcf->nbuckets <= 0 || szcf->nstreams <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
idx = ngx_hash_key(name->data, name->len) % szcf->nbuckets;
|
||||
|
||||
ngx_shmtx_lock(&szcf->hash[idx].mutex);
|
||||
cur = -1;
|
||||
next = szcf->hash[idx].node;
|
||||
while (next != -1) {
|
||||
if (ngx_strlen(szcf->stream_node[next].name) == name->len
|
||||
&& ngx_memcmp(szcf->stream_node[next].name, name->data, name->len)
|
||||
== 0)
|
||||
{
|
||||
if (szcf->stream_node[next].slot != ngx_process_slot) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur == -1) { /* link header */
|
||||
szcf->hash[idx].node = szcf->stream_node[next].next;
|
||||
} else {
|
||||
szcf->stream_node[cur].next = szcf->stream_node[next].next;
|
||||
}
|
||||
ngx_stream_zone_put_node(next);
|
||||
break;
|
||||
}
|
||||
|
||||
cur = next;
|
||||
next = szcf->stream_node[next].next;
|
||||
}
|
||||
ngx_shmtx_unlock(&szcf->hash[idx].mutex);
|
||||
}
|
||||
|
||||
ngx_chain_t *
|
||||
ngx_stream_zone_state(ngx_http_request_t *r, ngx_flag_t detail)
|
||||
{
|
||||
ngx_stream_zone_conf_t *szcf;
|
||||
ngx_chain_t *cl;
|
||||
ngx_buf_t *b;
|
||||
size_t len;
|
||||
volatile ngx_int_t idx, next;
|
||||
|
||||
szcf = (ngx_stream_zone_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_stream_zone_module);
|
||||
|
||||
if (szcf->nbuckets <= 0 || szcf->nstreams <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = sizeof("##########stream zone state##########\n") - 1
|
||||
+ sizeof("ngx_stream_zone buckets: \n") - 1 + NGX_OFF_T_LEN
|
||||
+ sizeof("ngx_stream_zone streams: \n") - 1 + NGX_OFF_T_LEN
|
||||
+ sizeof("ngx_stream_zone alloc: \n") - 1 + NGX_OFF_T_LEN;
|
||||
|
||||
cl = ngx_alloc_chain_link(r->pool);
|
||||
if (cl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cl->next = NULL;
|
||||
|
||||
b = ngx_create_temp_buf(r->pool, len);
|
||||
if (b == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
cl->buf = b;
|
||||
|
||||
b->last = ngx_snprintf(b->last, len,
|
||||
"##########stream zone state##########\n"
|
||||
"ngx_stream_zone buckets: %i\nngx_stream_zone streams: %i\n"
|
||||
"ngx_stream_zone alloc: %i\n",
|
||||
szcf->nbuckets, szcf->nstreams, *szcf->alloc);
|
||||
|
||||
if (detail) {
|
||||
for (idx = 0; idx < szcf->nbuckets; ++idx) {
|
||||
ngx_shmtx_lock(&szcf->hash[idx].mutex);
|
||||
|
||||
next = szcf->hash[idx].node;
|
||||
if (next == -1) {
|
||||
ngx_shmtx_unlock(&szcf->hash[idx].mutex);
|
||||
continue;
|
||||
}
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "slot: %i", idx);
|
||||
|
||||
while (next != -1) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"\t\tname:%s, slot:%i, idx:%i, next:%i",
|
||||
szcf->stream_node[next].name,
|
||||
szcf->stream_node[next].slot,
|
||||
szcf->stream_node[next].idx,
|
||||
szcf->stream_node[next].next);
|
||||
|
||||
next = szcf->stream_node[next].next;
|
||||
}
|
||||
|
||||
ngx_shmtx_unlock(&szcf->hash[idx].mutex);
|
||||
}
|
||||
}
|
||||
|
||||
return cl;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_ZONE_MODULE_H_INCLUDED_
|
||||
#define _NGX_STREAM_ZONE_MODULE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
/*
|
||||
* return value:
|
||||
* process_slot for owner of stream, NGX_ERROR for error
|
||||
* name:
|
||||
* stream name
|
||||
*/
|
||||
ngx_int_t ngx_stream_zone_insert_stream(ngx_str_t *name);
|
||||
|
||||
/*
|
||||
* name:
|
||||
* stream name
|
||||
*/
|
||||
void ngx_stream_zone_delete_stream(ngx_str_t *name);
|
||||
|
||||
/*
|
||||
* return value:
|
||||
* chain of stream zone state for returning to http client
|
||||
* paras:
|
||||
* r: http request to query status of rbuf
|
||||
* detail: print stream detail in log
|
||||
*/
|
||||
ngx_chain_t *ngx_stream_zone_state(ngx_http_request_t *r, ngx_flag_t detail);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
ngx_addon_name=ngx_multiport_test_module
|
||||
|
||||
HTTP_MODULES="$HTTP_MODULES \
|
||||
ngx_stream_zone_test_module \
|
||||
ngx_multiport_test_module \
|
||||
"
|
||||
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS
|
||||
$ngx_addon_dir/ngx_stream_zone_test_module.c \
|
||||
$ngx_addon_dir/ngx_multiport_test_module.c \
|
||||
"
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
user root;
|
||||
worker_processes 4;
|
||||
|
||||
#error_log logs/error.log;
|
||||
#error_log logs/error.log notice;
|
||||
error_log logs/error.log info;
|
||||
|
||||
#pid logs/nginx.pid;
|
||||
|
||||
stream_zone buckets=10007 streams=10000;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
multi_listen 9000 80;
|
||||
multi_listen unix:/tmp/http.sock.80 80;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
# '$status $body_bytes_sent "$http_referer" '
|
||||
# '"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
#access_log logs/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
location /stream_zone_test/ {
|
||||
stream_zone_test;
|
||||
}
|
||||
|
||||
location /multiport_test/ {
|
||||
inner_proxy unix:/tmp/http.sock.80 /inner_proxy;
|
||||
multiport_test;
|
||||
}
|
||||
|
||||
location /inner_proxy/ {
|
||||
rewrite ^/inner_proxy/(.*):/(.*) /$2 break;
|
||||
proxy_pass http://$1:;
|
||||
}
|
||||
|
||||
location / {
|
||||
broadcast unix:/tmp/http.sock.80 /auth_proxy;
|
||||
}
|
||||
|
||||
location /auth_proxy/ {
|
||||
rewrite ^/auth_proxy/(.*) /auth break;
|
||||
proxy_pass http://$1:;
|
||||
}
|
||||
|
||||
location /auth {
|
||||
# return 403;
|
||||
echo "auth";
|
||||
echo $scheme://$host$uri?$args;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include "ngx_multiport.h"
|
||||
#include "ngx_test_macro.h"
|
||||
|
||||
|
||||
static char *ngx_multiport_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
|
||||
|
||||
static ngx_command_t ngx_multiport_test_commands[] = {
|
||||
|
||||
{ ngx_string("multiport_test"),
|
||||
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
|
||||
ngx_multiport_test,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_multiport_test_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
NULL, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
NULL, /* create location configuration */
|
||||
NULL /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_multiport_test_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_multiport_test_module_ctx, /* module context */
|
||||
ngx_multiport_test_commands, /* module directives */
|
||||
NGX_HTTP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_multiport_test_get_port(ngx_http_request_t *r, char *multiport,
|
||||
ngx_int_t pslot, char *expect)
|
||||
{
|
||||
ngx_str_t port;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t mp;
|
||||
|
||||
mp.data = (u_char *) multiport;
|
||||
mp.len = ngx_strlen(multiport);
|
||||
|
||||
ngx_memzero(&port, sizeof(ngx_str_t));
|
||||
rc = ngx_multiport_get_port(r->pool, &port, &mp, pslot);
|
||||
if (port.len) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "port: %V, %s, %d",
|
||||
&port, port.data, port.len);
|
||||
}
|
||||
if (expect == NULL && rc == NGX_ERROR) {
|
||||
return 1;
|
||||
} else {
|
||||
return ngx_test_str(&port, expect);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_multiport_test_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_buf_t *b;
|
||||
ngx_chain_t cl;
|
||||
size_t len;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"multiport test handler");
|
||||
|
||||
rc = ngx_http_inner_proxy_request(r, ngx_multiport_get_slot(0));
|
||||
if (rc != NGX_DECLINED) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"inner proxy return %i", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
NGX_TEST_INIT
|
||||
|
||||
/* test ngx_multiport_get_port */
|
||||
/* normal format */
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "10", 127, "137"));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "127.0.0.1:55635", 4,
|
||||
"127.0.0.1:55639"));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "[::127.0.0.1]:1024", 0,
|
||||
"[::127.0.0.1]:1024"));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "unix:/tmp.test", 7,
|
||||
"unix:/tmp.test.7"));
|
||||
|
||||
/* inet6 format error */
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "[::127.0.0.1:1024", 0, NULL));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "[::127.0.0.1]:abcd",
|
||||
0, NULL));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "[::127.0.0.1]:65409",
|
||||
0, NULL));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "[::127.0.0.1]:", 0, NULL));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "[::127.0.0.1]", 0, NULL));
|
||||
|
||||
/* inet format error */
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "127.0.0.1:", 4, NULL));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "abcd", 4, NULL));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "65410", 4, NULL));
|
||||
|
||||
/* pslot error */
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "65410", -1, NULL));
|
||||
NGX_TEST_ISOK(ngx_multiport_test_get_port(r, "65410", 128, NULL));
|
||||
|
||||
/* test ngx_multiport_get_slot */
|
||||
NGX_TEST_ISOK(ngx_multiport_get_slot(4) == -1);
|
||||
NGX_TEST_ISOK(ngx_multiport_get_slot(0) == 0);
|
||||
NGX_TEST_ISOK(ngx_multiport_get_slot(1) == 1);
|
||||
NGX_TEST_ISOK(ngx_multiport_get_slot(2) == 2);
|
||||
NGX_TEST_ISOK(ngx_multiport_get_slot(3) == 3);
|
||||
|
||||
r->headers_out.status = NGX_HTTP_OK;
|
||||
|
||||
ngx_http_send_header(r);
|
||||
|
||||
len = sizeof("pslot: %i TEST cases 4294967296, 4294967296 pass\n") - 1;
|
||||
b = ngx_create_temp_buf(r->pool, len);
|
||||
|
||||
if (b == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
b->last = ngx_snprintf(b->last, len, "pslot: %i TEST cases %d, %d pass\n",
|
||||
ngx_process_slot, count, pass);
|
||||
b->last_buf = 1;
|
||||
b->last_in_chain = 1;
|
||||
|
||||
cl.buf = b;
|
||||
cl.next = NULL;
|
||||
|
||||
return ngx_http_output_filter(r, &cl);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_multiport_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
|
||||
clcf->handler = ngx_multiport_test_handler;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include "ngx_stream_zone_module.h"
|
||||
|
||||
|
||||
static char *ngx_stream_zone_test(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
static ngx_command_t ngx_stream_zone_test_commands[] = {
|
||||
|
||||
{ ngx_string("stream_zone_test"),
|
||||
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
|
||||
ngx_stream_zone_test,
|
||||
0,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
|
||||
static ngx_http_module_t ngx_stream_zone_test_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
NULL, /* postconfiguration */
|
||||
|
||||
NULL, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
|
||||
NULL, /* create location configuration */
|
||||
NULL /* merge location configuration */
|
||||
};
|
||||
|
||||
|
||||
ngx_module_t ngx_stream_zone_test_module = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_stream_zone_test_module_ctx, /* module context */
|
||||
ngx_stream_zone_test_commands, /* module directives */
|
||||
NGX_HTTP_MODULE, /* module type */
|
||||
NULL, /* init master */
|
||||
NULL, /* init module */
|
||||
NULL, /* init process */
|
||||
NULL, /* init thread */
|
||||
NULL, /* exit thread */
|
||||
NULL, /* exit process */
|
||||
NULL, /* exit master */
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_zone_test_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_chain_t cl, *out;
|
||||
ngx_buf_t *b;
|
||||
size_t len;
|
||||
ngx_str_t stream;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "stream zone test handler");
|
||||
|
||||
rc = -1;
|
||||
if (r->method == NGX_HTTP_GET) {
|
||||
out = ngx_stream_zone_state(r, 1);
|
||||
out->buf->last_buf = 1;
|
||||
out->buf->last_in_chain = 1;
|
||||
|
||||
r->headers_out.status = NGX_HTTP_OK;
|
||||
ngx_http_send_header(r);
|
||||
|
||||
return ngx_http_output_filter(r, out);
|
||||
} else if (r->method == NGX_HTTP_DELETE) {
|
||||
|
||||
if (ngx_http_arg(r, (u_char *) "stream", 6, &stream) != NGX_OK) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"stream zone test, no stream in http args");
|
||||
return NGX_HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
len = sizeof("delete stream=\n") - 1 + stream.len;
|
||||
|
||||
ngx_stream_zone_delete_stream(&stream);
|
||||
} else if (r->method == NGX_HTTP_POST) {
|
||||
|
||||
if (ngx_http_arg(r, (u_char *) "stream", 6, &stream) != NGX_OK) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"stream zone test, no stream in http args");
|
||||
return NGX_HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
len = sizeof("stream= in process:4294967296\n") - 1 + stream.len;
|
||||
|
||||
rc = ngx_stream_zone_insert_stream(&stream);
|
||||
} else {
|
||||
return NGX_HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
r->headers_out.status = NGX_HTTP_OK;
|
||||
ngx_http_send_header(r);
|
||||
|
||||
b = ngx_create_temp_buf(r->pool, len);
|
||||
|
||||
if (b == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (r->method == NGX_HTTP_DELETE) {
|
||||
b->last = ngx_snprintf(b->last, len, "delete stream=%V\n", &stream);
|
||||
} else {
|
||||
b->last = ngx_snprintf(b->last, len,
|
||||
"stream=%V in process:%i\n", &stream, rc);
|
||||
}
|
||||
b->last_buf = 1;
|
||||
b->last_in_chain = 1;
|
||||
|
||||
cl.buf = b;
|
||||
cl.next = NULL;
|
||||
|
||||
return ngx_http_output_filter(r, &cl);
|
||||
}
|
||||
|
||||
static char *
|
||||
ngx_stream_zone_test(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
|
||||
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
|
||||
clcf->handler = ngx_stream_zone_test_handler;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) AlexWoo(Wu Jie) wj19840501@gmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_TEST_MACRO_H_INCLUDE_
|
||||
#define _NGX_TEST_MACRO_H_INCLUDE_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
static ngx_int_t count = 0;
|
||||
static ngx_int_t pass = 0;
|
||||
|
||||
#define NGX_TEST_INIT count = 0, pass = 0;
|
||||
|
||||
#define NGX_TEST_ISOK(testcase) \
|
||||
{ \
|
||||
ngx_int_t __ret = testcase; \
|
||||
++count; \
|
||||
if (__ret) ++pass; \
|
||||
ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, " TEST "#testcase"%s",\
|
||||
(__ret ? " ...OK" : " ...ERROR")); \
|
||||
}
|
||||
|
||||
#define NGX_TEST_INT(di, si) \
|
||||
(di == si)
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_test_str(ngx_str_t *nstr, char *cstr)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = ngx_strlen(cstr);
|
||||
|
||||
return (nstr->len == len && ngx_memcmp(nstr->data, cstr, len) == 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
Project author:
|
||||
|
||||
Roman Arutyunyan
|
||||
Moscow, Russia, Pingo
|
||||
|
||||
Contacts:
|
||||
arut@qip.ru
|
||||
arutyunyan.roman@gmail.com
|
||||
cczjp89@gmail.com
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user