Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions emhttp/languages/en_US/helptext.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2379,6 +2379,12 @@ Generally speaking, it is recommended to leave this setting to its default value
IMPORTANT NOTE: If adjusting port mappings, do not modify the settings for the Container port as only the Host port can be adjusted.
:end

:docker_fixed_mac_help:
Assigns the container's MAC address on the selected Docker network endpoint. Use a valid unicast MAC address; the first octet must be even, e.g. 02:42:9a:0d:7e:c0.

This avoids using the legacy container-level --mac-address option in Extra Parameters.
:end

:docker_container_network_help:
This allows your container to utilize the network configuration of another container. Select the appropriate container from the list.<br>This setup can be particularly beneficial if you wish to route your container's traffic through a VPN.
:end
Expand Down
36 changes: 28 additions & 8 deletions emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,18 +202,17 @@ function cpu_pinning() {
if (preg_match('/^container:(.*)/', $Network)) {
$Net_Container = str_replace("container:", "", $Network);
} else {
preg_match("/--(net|network)=container:[^\s]+/", $ExtraParams, $NetworkParam);
if (!empty($NetworkParam[0])) {
$Net_Container = explode(':', $NetworkParam[0])[1];
$Net_Container = str_replace(['"', "'"], '', $Net_Container);
preg_match("/--(?:net|network)(?:=|\s+)(['\"]?)container:([^'\"\s]+)\\1/", $ExtraParams, $NetworkParam);
if (!empty($NetworkParam[2])) {
$Net_Container = $NetworkParam[2];
}
}
// check if the container still exists from which the network should be used, if it doesn't exist any more recreate container with network none and don't start it
if (!empty($Net_Container)) {
$Net_Container_ID = $DockerClient->getContainerID($Net_Container);
if (empty($Net_Container_ID)) {
$cmd = str_replace('/docker run -d ', '/docker create ', $cmd);
$cmd = preg_replace("/--(net|network)=(['\"]?)container:[^'\"]+\\2/", "--network=none ", $cmd);
$cmd = preg_replace("/--(?:net|network)(?:=|\s+)(['\"]?)container:[^'\"\s]+\\1/", "--network=none ", $cmd);
}
}
// force kill container if still running after time-out
Expand Down Expand Up @@ -736,6 +735,8 @@ function removeConfig(num) {

function prepareConfig(form) {
var types = [], values = [], targets = [], vcpu = [];
var myMAC = $(form).find('input[name="contMyMAC"]').val().trim().replaceAll('-', ':').toLowerCase();
$(form).find('input[name="contMyMAC"]').val(myMAC);
if ($('select[name="contNetwork"]').val()=='host') {
$(form).find('input[name="confType[]"]').each(function(){types.push($(this).val());});
$(form).find('input[name="confValue[]"]').each(function(){values.push($(this));});
Expand All @@ -744,6 +745,7 @@ function prepareConfig(form) {
}
$(form).find('input[id^="box"]').each(function(){if ($(this).prop('checked')) vcpu.push($('#'+$(this).prop('id').replace('box','cpu')).text());});
form.contCPUset.value = vcpu.join(',');
return true;
}

function makeName(type) {
Expand Down Expand Up @@ -893,7 +895,7 @@ function prepareCategory() {
?>

<div id="canvas">
<form markdown="1" method="POST" autocomplete="off" onsubmit="prepareConfig(this)">
<form markdown="1" method="POST" autocomplete="off" onsubmit="return prepareConfig(this)">
<input type="hidden" name="csrf_token" value="<?=$var['csrf_token']?>">
<input type="hidden" name="contCPUset" value="">
<?if ($xmlType=='edit'):?>
Expand Down Expand Up @@ -1111,6 +1113,14 @@ function prepareCategory() {

</div>

<div markdown="1" class="myMAC noshow">
_(Fixed MAC address)_ (_(optional)_):
: <input type="text" name="contMyMAC" pattern="([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}|[0-9A-Fa-f]{12}">

:docker_fixed_mac_help:

</div>

<div markdown="1" class="netCONT noshow">
_(Container Network)_:
: <select name="netCONT" id="netCONT">
Expand Down Expand Up @@ -1560,19 +1570,30 @@ function prepareCategory() {
<?endforeach;?>

function showSubnet(bridge) {
if (bridge.match(/^(bridge|host|none)$/i) !== null) {
if (bridge.match(/^(host|none)$/i) !== null) {
$('.myIP').hide();
$('input[name="contMyIP"]').val('');
$('.myMAC').hide();
$('input[name="contMyMAC"]').val('');
$('.netCONT').hide();
$('#netCONT').val('');
} else if (bridge.match(/^(bridge)$/i) !== null) {
$('.myIP').hide();
$('input[name="contMyIP"]').val('');
$('.myMAC').show();
$('.netCONT').hide();
$('#netCONT').val('');
} else if (bridge.match(/^(container)$/i) !== null) {
$('.netCONT').show();
$('#netCONT').val('<?php echo (isset($xml) && isset($xml['Network'][1])) ? $xml['Network'][1] : ''; ?>');
$('.myIP').hide();
$('input[name="contMyIP"]').val('');
$('.myMAC').hide();
$('input[name="contMyMAC"]').val('');
} else {
$('.myIP').show();
$('#myIP').html('<?=_('Subnet')?>: '+subnet[bridge]);
$('.myMAC').show();
$('.netCONT').hide();
$('#netCONT').val('');
}
Expand Down Expand Up @@ -1932,4 +1953,3 @@ function load_contOverview() {
}
</script>
<?END:?>

94 changes: 88 additions & 6 deletions emhttp/plugins/dynamix.docker.manager/include/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,66 @@ function xml_decode($string) {
return strval(html_entity_decode($string, ENT_XML1, 'UTF-8'));
}

function extraParamsWithQuotedValuesMasked($extraParams) {
return preg_replace('/"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\']*\'/', '""', $extraParams);
}

function replaceUnquotedExtraParams($extraParams, $callback) {
$parts = preg_split('/("[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\']*\')/', $extraParams, -1, PREG_SPLIT_DELIM_CAPTURE);
if ($parts === false) {
return $extraParams;
}
foreach ($parts as $i => $part) {
if ($part === '' || $part[0] === '"' || $part[0] === "'") {
continue;
}
$parts[$i] = $callback($part);
}
return implode('', $parts);
}

function extractMacAddressParam($extraParams) {
if (!is_string($extraParams)) {
return '';
}
$extraParams = extraParamsWithQuotedValuesMasked($extraParams);
if (preg_match('/(?:^|\s)--mac-address=([^\s\'"]+)/', $extraParams, $match)) {
return trim($match[1]);
}
if (preg_match('/(?:^|\s)--mac-address\s+([^\s\'"]+)/', $extraParams, $match)) {
return trim($match[1]);
}
return '';
}

function removeMacAddressParam($extraParams) {
if (!is_string($extraParams) || $extraParams === '') {
return '';
}
$extraParams = replaceUnquotedExtraParams($extraParams, function($part) {
$part = preg_replace('/(^|\s)--mac-address=[^\s\'"]+/', '$1', $part);
return preg_replace('/(^|\s)--mac-address\s+[^\s\'"]+/', '$1', $part);
});
return trim($extraParams);
}

function hasNetworkParam($extraParams) {
return is_string($extraParams) && preg_match('/(?:^|\s)--net(?:work)?(?:=|\s+)[^\s\'"]+/', extraParamsWithQuotedValuesMasked($extraParams));
}

function normalizeMacAddress($mac) {
$mac = strtolower(trim($mac ?? ''));
if ($mac === '') {
return '';
}
if (preg_match('/^[0-9a-f]{12}$/', $mac)) {
$mac = implode(':', str_split($mac, 2));
} else {
$mac = str_replace('-', ':', $mac);
}
return preg_match('/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/', $mac) ? $mac : '';
Comment on lines +82 to +92
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't silently drop invalid Fixed MAC input.

normalizeMacAddress() collapses any non-normalizable value to '', and both postToXML() and xmlToVar() persist only that normalized result. If a user types an invalid MAC in the new field, the template quietly clears it instead of preserving the value and letting Docker reject the create. That loses user input and bypasses the intended Docker-owned error path.

Proposed fix
-  $myMAC                           = $extraNetwork ? '' : normalizeMacAddress(trim($post['contMyMAC'] ?? '') ?: extractMacAddressParam($post['contExtraParams'] ?? ''));
+  $rawMyMAC                        = trim($post['contMyMAC'] ?? '');
+  $legacyMyMAC                     = extractMacAddressParam($post['contExtraParams'] ?? '');
+  $myMAC                           = $extraNetwork ? '' : ($rawMyMAC !== '' ? (normalizeMacAddress($rawMyMAC) ?: $rawMyMAC) : normalizeMacAddress($legacyMyMAC));
   $xml->MyMAC                      = xml_encode($myMAC);
-  $out['MyMAC']                        = $extraNetwork ? '' : normalizeMacAddress(xml_decode($xml->MyMAC ?? '') ?: extractMacAddressParam($extraParams));
+  $storedMyMAC                         = xml_decode($xml->MyMAC ?? '');
+  $out['MyMAC']                        = $extraNetwork ? '' : ($storedMyMAC !== '' ? (normalizeMacAddress($storedMyMAC) ?: $storedMyMAC) : normalizeMacAddress(extractMacAddressParam($extraParams)));

Also applies to: 138-151, 215-228

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@emhttp/plugins/dynamix.docker.manager/include/Helpers.php` around lines 82 -
92, normalizeMacAddress() currently returns an empty string for any
non-normalizable MAC which causes postToXML() and xmlToVar() to silently drop
user input; change normalizeMacAddress($mac) to return the original trimmed
input (not '') when the value fails validation so the raw value is preserved,
and update callers postToXML() and xmlToVar() (the logic around persisting the
Fixed MAC field) to use the raw input when normalizeMacAddress indicates invalid
(i.e., do not overwrite user input with an empty string) so Docker can perform
its own rejection; ensure the function still normalizes valid 12-hex or dash
formats into colon-separated lowercase and only returns '' for an originally
empty/blank input.

}

function generateTSwebui($url, $serve, $webUI) {
if (!isset($webUI)) {
return '';
Expand Down Expand Up @@ -75,6 +135,9 @@ function postToXML($post, $setOwnership=false) {
$xml->Network = xml_encode($post['contNetwork']);
}
$xml->MyIP = xml_encode($post['contMyIP']);
$extraNetwork = hasNetworkParam($post['contExtraParams'] ?? '');
$myMAC = $extraNetwork ? '' : normalizeMacAddress(trim($post['contMyMAC'] ?? '') ?: extractMacAddressParam($post['contExtraParams'] ?? ''));
$xml->MyMAC = xml_encode($myMAC);
$xml->Shell = xml_encode($post['contShell']);
$xml->Privileged = strtolower($post['contPrivileged']??'')=='on' ? 'true' : 'false';
$xml->Support = xml_encode($post['contSupport']);
Expand All @@ -85,7 +148,7 @@ function postToXML($post, $setOwnership=false) {
$xml->WebUI = xml_encode(trim($post['contWebUI']));
$xml->TemplateURL = xml_encode($post['contTemplateURL']);
$xml->Icon = xml_encode(trim($post['contIcon']));
$xml->ExtraParams = xml_encode($post['contExtraParams']);
$xml->ExtraParams = xml_encode($myMAC && !$extraNetwork ? removeMacAddressParam($post['contExtraParams']) : $post['contExtraParams']);
$xml->PostArgs = xml_encode($post['contPostArgs']);
$xml->CPUset = xml_encode($post['contCPUset']);
$xml->DateInstalled = xml_encode(time());
Expand Down Expand Up @@ -149,6 +212,9 @@ function xmlToVar($xml) {
$out['Registry'] = xml_decode($xml->Registry);
$out['Network'] = xml_decode($xml->Network);
$out['MyIP'] = xml_decode($xml->MyIP ?? '');
$extraParams = xml_decode($xml->ExtraParams ?? '');
$extraNetwork = hasNetworkParam($extraParams);
$out['MyMAC'] = $extraNetwork ? '' : normalizeMacAddress(xml_decode($xml->MyMAC ?? '') ?: extractMacAddressParam($extraParams));
$out['Shell'] = xml_decode($xml->Shell ?? 'sh');
$out['Privileged'] = xml_decode($xml->Privileged);
$out['Support'] = xml_decode($xml->Support);
Expand All @@ -159,7 +225,7 @@ function xmlToVar($xml) {
$out['WebUI'] = xml_decode($xml->WebUI);
$out['TemplateURL'] = xml_decode($xml->TemplateURL);
$out['Icon'] = xml_decode($xml->Icon);
$out['ExtraParams'] = xml_decode($xml->ExtraParams);
$out['ExtraParams'] = $extraParams;
$out['PostArgs'] = xml_decode($xml->PostArgs);
$out['CPUset'] = xml_decode($xml->CPUset);
$out['DonateText'] = xml_decode($xml->DonateText);
Expand Down Expand Up @@ -325,13 +391,29 @@ function xmlToCommand($xml, $create_paths=false) {
$xml = xmlToVar($xml);
$cmdName = strlen($xml['Name']) ? '--name='.escapeshellarg($xml['Name']) : '';
$cmdPrivileged = strtolower($xml['Privileged'])=='true' ? '--privileged=true' : '';
$extraNetwork = hasNetworkParam($xml['ExtraParams']);
$cmdMyIP = '';
if (preg_match('/^container:(.*)/', $xml['Network'])) {
$cmdNetwork = preg_match('/\-\-net(work)?=/',$xml['ExtraParams']) ? "" : '--net='.escapeshellarg($xml['Network']);
$cmdNetwork = $extraNetwork ? "" : '--net='.escapeshellarg($xml['Network']);
} else {
$cmdNetwork = preg_match('/\-\-net(work)?=/',$xml['ExtraParams']) ? "" : '--net='.escapeshellarg(strtolower($xml['Network']));
$networkName = strtolower($xml['Network']);
if ($extraNetwork) {
$cmdNetwork = "";
} elseif (strlen($xml['MyMAC']) && !in_array($networkName, ['host','none'])) {
$xml['ExtraParams'] = removeMacAddressParam($xml['ExtraParams']);
$networkEndpoint = ['name='.$networkName];
foreach (explode(' ',str_replace(',',' ',$xml['MyIP'])) as $myIP) {
if ($myIP) $networkEndpoint[] = (strpos($myIP,':') !== false ? 'ip6=' : 'ip=').$myIP;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
$networkEndpoint[] = 'mac-address='.$xml['MyMAC'];
$cmdNetwork = '--network='.escapeshellarg(implode(',', $networkEndpoint));
} else {
$cmdNetwork = '--net='.escapeshellarg($networkName);
Comment on lines +399 to +411
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Are mixed-case Docker network names valid in Docker Engine, and are they matched case-sensitively when passed through docker create --network/docker run --network?

💡 Result:

Yes, mixed-case Docker network names are valid in Docker Engine. They are matched case-sensitively when passed through docker create --network or docker run --network. Docker network names have minimal validation restrictions compared to container or volume names. Unlike containers/volumes which follow a strict regex [a-zA-Z0-9][a-zA-Z0-9_.-]*, networks historically allowed broader characters (e.g., %, ^) as long as non-empty, though later versions tightened some rules for consistency. Official docs do not prohibit uppercase letters, and community reports confirm mixed-case names like "ThIsIsANeTWoRk" can be created successfully. Network matching by name in --network is case-sensitive because Docker stores and lists network names preserving case (e.g., docker network ls shows exact case), and Linux filesystems (where Docker stores network config under /var/lib/docker/network/files/local) are case-sensitive. When specifying a partial ID, Docker resolves it to the name first, then matches, confirming case-exact name lookup. No sources indicate case-insensitive name matching for networks; contrasts with container DNS resolution (which became case-insensitive in later versions via libnetwork changes).

Citations:


🏁 Script executed:

# First, let's check the file and see the full context of this function
cd /root && find . -type f -name "Helpers.php" | head -20

Repository: unraid/webgui

Length of output: 112


🏁 Script executed:

# Examine the file with line numbers, showing context around the target lines
if [ -f "./emhttp/plugins/dynamix.docker.manager/include/Helpers.php" ]; then
  wc -l "./emhttp/plugins/dynamix.docker.manager/include/Helpers.php"
fi

Repository: unraid/webgui

Length of output: 120


🏁 Script executed:

# Get the full function context - find the function this code belongs to
rg -B 30 'strtolower\(\$xml\[.Network.\]\)' --context 3 ./emhttp/plugins/dynamix.docker.manager/include/Helpers.php | head -80

Repository: unraid/webgui

Length of output: 387


🏁 Script executed:

# Check how $xml['Network'] is used elsewhere in the file before this point
rg '\$xml\[.Network.\]' --context 2 ./emhttp/plugins/dynamix.docker.manager/include/Helpers.php

Repository: unraid/webgui

Length of output: 804


🏁 Script executed:

# Get broader context of the function - search backwards to find the function signature
sed -n '350,420p' ./emhttp/plugins/dynamix.docker.manager/include/Helpers.php | cat -n

Repository: unraid/webgui

Length of output: 3339


🏁 Script executed:

# Look for the function name and its start
rg 'function.*\{' -B 5 ./emhttp/plugins/dynamix.docker.manager/include/Helpers.php | grep -A 10 'xmlToCommand'

Repository: unraid/webgui

Length of output: 1301


🏁 Script executed:

# Get the complete section around lines 390-420 to see the full logic
sed -n '390,420p' ./emhttp/plugins/dynamix.docker.manager/include/Helpers.php | cat -n

Repository: unraid/webgui

Length of output: 1893


Preserve the configured network name when emitting CLI arguments.

The code lowercases $xml['Network'] unconditionally at line 399, then uses that lowercased name in network endpoint definitions and --net= / --network= commands. Docker matches network names case-sensitively, so a custom network named "MyNetwork" would fail when the code passes "mynetwork" to Docker.

The strtolower() is only needed for the case-insensitive check against the special modes ['host','none'] at line 407. The original network name should be preserved for command emission.

Proposed fix
-    $networkName = strtolower($xml['Network']);
+    $networkName = $xml['Network'];
+    $networkMode = strtolower($networkName);
     if ($extraNetwork) {
       $cmdNetwork = "";
-    } elseif (strlen($xml['MyMAC']) && !in_array($networkName, ['host','none'])) {
+    } elseif (strlen($xml['MyMAC']) && !in_array($networkMode, ['host','none'])) {
       $xml['ExtraParams'] = removeMacAddressParam($xml['ExtraParams']);
       $networkEndpoint = ['name='.$networkName];
       foreach (explode(' ',str_replace(',',' ',$xml['MyIP'])) as $myIP) {
         if ($myIP) $networkEndpoint[] = (strpos($myIP,':') !== false ? 'ip6=' : 'ip=').$myIP;
       }
       $networkEndpoint[] = 'mac-address='.$xml['MyMAC'];
       $cmdNetwork = '--network='.escapeshellarg(implode(',', $networkEndpoint));
     } else {
       $cmdNetwork  = '--net='.escapeshellarg($networkName);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@emhttp/plugins/dynamix.docker.manager/include/Helpers.php` around lines 399 -
411, The code lowercases $xml['Network'] into $networkName and then uses it when
emitting Docker CLI args; Docker is case-sensitive so preserve the original
network name. Change the logic so you keep the original name (e.g., $origNetwork
= $xml['Network']) and only use a lowercased copy (e.g., $networkCheck =
strtolower($origNetwork)) for the special-case check against ['host','none'];
then use the original name ($origNetwork) when building $networkEndpoint,
setting 'name=...', and when assigning $cmdNetwork for both the '--network=' and
'--net=' branches while keeping the existing removeMacAddressParam,
$networkEndpoint assembly, and escapeshellarg usage intact.

}
}
if (!strlen($xml['MyMAC']) || preg_match('/^container:(.*)/', $xml['Network']) || $extraNetwork) {
foreach (explode(' ',str_replace(',',' ',$xml['MyIP'])) as $myIP) if ($myIP) $cmdMyIP .= (strpos($myIP,':') !== false ? '--ip6=' : '--ip=').escapeshellarg($myIP).' ';
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
$cmdMyIP = '';
foreach (explode(' ',str_replace(',',' ',$xml['MyIP'])) as $myIP) if ($myIP) $cmdMyIP .= (strpos($myIP,':')?'--ip6=':'--ip=').escapeshellarg($myIP).' ';
$cmdCPUset = strlen($xml['CPUset']) ? '--cpuset-cpus='.escapeshellarg($xml['CPUset']) : '';
$Volumes = [''];
$Ports = [''];
Expand Down
58 changes: 48 additions & 10 deletions etc/rc.d/rc.docker
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,16 @@ netrestore_connect(){
local MY_TT=$3
local MY_MAC=$4
local MY_IP=
local MY_OPTS=
local MY_IPV4=
local MY_IPV6=
local IP=
local IPAM_JSON=
local ENDPOINT_JSON=
local CONNECT_JSON=
local CODE=
local BODY=
local ENDPOINT_ID=
local ENDPOINT_MAC=
local OUT=

container_exist "$CONTAINER" || return 0
Expand All @@ -263,23 +270,49 @@ netrestore_connect(){
return 1
fi

ENDPOINT_ID=$(docker inspect --format="{{with index .NetworkSettings.Networks \"$NETWORK\"}}{{.EndpointID}}{{end}}" "$CONTAINER" 2>/dev/null)
[[ -n $ENDPOINT_ID ]] && return 0

for IP in ${MY_TT//;/ }; do
[[ -n $IP ]] || continue
if [[ $IP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
MY_IPV4=$IP
MY_IP="$MY_IP --ip $IP"
elif [[ $IP =~ : ]]; then
MY_IPV6=$IP
MY_IP="$MY_IP --ip6 $IP"
else
log "skipping invalid stored IP for $CONTAINER on network $NETWORK: $IP"
fi
done

[[ -n $MY_MAC ]] && MY_OPTS="--driver-opt=com.docker.network.endpoint.macaddress=$MY_MAC"
ENDPOINT_ID=$(docker inspect --format="{{with index .NetworkSettings.Networks \"$NETWORK\"}}{{.EndpointID}}{{end}}" "$CONTAINER" 2>/dev/null)
if [[ -n $ENDPOINT_ID ]]; then
[[ -n $MY_MAC ]] || return 0
ENDPOINT_MAC=$(docker inspect --format="{{with index .NetworkSettings.Networks \"$NETWORK\"}}{{.MacAddress}}{{end}}" "$CONTAINER" 2>/dev/null)
[[ ${ENDPOINT_MAC,,} == ${MY_MAC,,} ]] && return 0
log "reconnecting $CONTAINER to network $NETWORK to restore MAC $MY_MAC"
if ! OUT=$(docker network disconnect -f "$NETWORK" "$CONTAINER" 2>&1); then
log "failed to disconnect $CONTAINER from network $NETWORK: $OUT"
return 1
fi
fi

if [[ -n $MY_MAC ]]; then
[[ -n $MY_IPV4 ]] && IPAM_JSON="\"IPv4Address\":\"$MY_IPV4\""
[[ -n $MY_IPV6 ]] && IPAM_JSON="${IPAM_JSON:+$IPAM_JSON,}\"IPv6Address\":\"$MY_IPV6\""
ENDPOINT_JSON="\"MacAddress\":\"$MY_MAC\""
[[ -n $IPAM_JSON ]] && ENDPOINT_JSON="\"IPAMConfig\":{$IPAM_JSON},$ENDPOINT_JSON"
CONNECT_JSON="{\"Container\":\"$CONTAINER\",\"EndpointConfig\":{$ENDPOINT_JSON}}"
OUT=$(curl --unix-socket /var/run/docker.sock -sS -w $'\n%{http_code}' -X POST -H "Content-Type: application/json" --data "$CONNECT_JSON" "http://localhost/networks/$NETWORK/connect" 2>&1)
CODE=${OUT##*$'\n'}
BODY=${OUT%$'\n'$CODE}
if [[ $CODE != 2* ]]; then
log "failed to connect $CONTAINER to network $NETWORK: $BODY"
return 1
fi
return 0
fi

log "connecting $CONTAINER to network $NETWORK"
if ! OUT=$(docker network connect $MY_OPTS $MY_IP $NETWORK $CONTAINER 2>&1); then
if ! OUT=$(docker network connect $MY_IP $NETWORK $CONTAINER 2>&1); then
log "failed to connect $CONTAINER to network $NETWORK: $OUT"
return 1
fi
Expand Down Expand Up @@ -347,20 +380,25 @@ docker_network_start(){
REBUILD=1
fi
done
MY_NETWORK= MY_IP= MY_MAC= TEMPLATE_MAC= CUSTOM_PRIMARY=
MY_NETWORK= MY_IP= MY_MAC= XML_MAC= TEMPLATE_MAC= CUSTOM_PRIMARY=
while read_dom; do
[[ $ENTITY == Network ]] && MY_NETWORK=$CONTENT
[[ $ENTITY == MyIP ]] && MY_IP=${CONTENT// /,} && MY_IP=$(echo "$MY_IP" | tr -s "," ";")
[[ $ENTITY == MyMAC ]] && XML_MAC=${CONTENT// /}
done <$XMLFILE
# only restore valid networks
if [[ -n $MY_NETWORK ]]; then
[[ $MY_NETWORK =~ ^(br|bond|eth|wlan)[0-9]+(\.[0-9]+)?$ ]] && CUSTOM_PRIMARY=1
TEMPLATE_MAC=$(sed -nE 's@.*<ExtraParams>.*--mac-address(=|[[:space:]]+)([^ <]+).*@\2@p' "$XMLFILE" | head -n1)
MY_MAC=$(docker inspect --format="{{with index .NetworkSettings.Networks \"$MY_NETWORK\"}}{{.MacAddress}}{{end}}" $CONTAINER 2>/dev/null)
[[ -n $MY_MAC ]] || MY_MAC=$TEMPLATE_MAC
if [[ -n $XML_MAC ]]; then
MY_MAC=$XML_MAC
else
MY_MAC=$(docker inspect --format="{{with index .NetworkSettings.Networks \"$MY_NETWORK\"}}{{.MacAddress}}{{end}}" $CONTAINER 2>/dev/null)
[[ -n $MY_MAC ]] || MY_MAC=$TEMPLATE_MAC
fi
netrestore_add "$MY_NETWORK" "$CONTAINER" "$MY_IP" "$MY_MAC"
PRIMARY_NETWORK[$CONTAINER]=$MY_NETWORK
[[ -n $REBUILD || (-n $TEMPLATE_MAC && -n $CUSTOM_PRIMARY) ]] && REBUILD_CONTAINERS[$CONTAINER]=1
[[ -n $REBUILD || (-z $XML_MAC && -n $TEMPLATE_MAC && -n $CUSTOM_PRIMARY) ]] && REBUILD_CONTAINERS[$CONTAINER]=1
fi
fi
# restore user defined networks
Expand Down
Loading