Skip to content
Open
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
439 changes: 373 additions & 66 deletions build-common.xml

Large diffs are not rendered by default.

135 changes: 135 additions & 0 deletions common/src/java-test/com/zimbra/common/util/NetUtilTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Zimbra Collaboration Suite Server
* Copyright (C) 2012, 2013, 2014, 2016, 2024 Synacor, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation,
* version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <https://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK *****
*/
package com.zimbra.common.util;

import java.net.InetAddress;

import org.junit.Assert;
import org.junit.Test;


public class NetUtilTest {
@Test
public void testIsInRangePrivateAddressesIPv4() throws Exception {
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("9.0.0.0"), "10.0.0.0/8"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("9.255.255.255"), "10.0.0.0/8"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("10.0.0.0"), "10.0.0.0/8"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("10.50.50.55"), "10.0.0.0/8"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("10.50.0.255"), "10.0.0.0/8"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("10.50.255.0"), "10.0.0.0/8"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("10.255.255.255"), "10.0.0.0/8"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("11.0.0.0"), "10.0.0.0/8"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("11.255.255.255"), "10.0.0.0/8"));

Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("172.15.255.255"), "172.16.0.0/12"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("172.15.0.0"), "172.16.0.0/12"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("172.16.0.0"), "172.16.0.0/12"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("172.16.50.50"), "172.16.0.0/12"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("172.16.0.255"), "172.16.0.0/12"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("172.16.255.0"), "172.16.0.0/12"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("172.31.255.255"), "172.16.0.0/12"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("172.32.0.0"), "172.16.0.0/12"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("172.32.255.255"), "172.16.0.0/12"));

Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("192.167.0.0"), "192.168.0.0/16"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("192.167.255.255"), "192.168.0.0/16"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("192.168.0.0"), "192.168.0.0/16"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("192.168.1.131"), "192.168.0.0/16"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("192.168.0.255"), "192.168.0.0/16"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("192.168.255.0"), "192.168.0.0/16"));
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("192.168.255.255"), "192.168.0.0/16"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("192.169.255.255"), "192.168.0.0/16"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("192.169.0.0"), "192.168.0.0/16"));
}

@Test
public void testIsInRangeTestAddressesIPv4() throws Exception {
for (int i = 0; i < 256; i++) {
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("198.51.100." + i), "198.51.100.0/24"));
}
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("198.50.100.0"), "198.51.100.0/24"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("198.50.100.255"), "198.51.100.0/24"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("198.52.100.0"), "198.51.100.0/24"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("198.52.100.255"), "198.51.100.0/24"));

for (int i = 0; i < 256; i++) {
Assert.assertTrue(NetUtil.isAddressInRange(InetAddress.getByName("203.0.113." + i), "203.0.113.0/24"));
}
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("203.0.112.0"), "203.0.113.0/24"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("203.0.112.255"), "203.0.113.0/24"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("203.0.114.0"), "203.0.113.0/24"));
Assert.assertFalse(NetUtil.isAddressInRange(InetAddress.getByName("203.0.114.255"), "203.0.113.0/24"));
}

@Test
public void testIsInRangePrivateAddressesIPv6() throws Exception {
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fedd:0d17:76f7:3e82:0000:0000:0000:0000"), "fddd:0d17:76f7:3e82::/64"));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fedd:0d17:76f7:3e82:ffff:ffff:ffff:ffff"), "fddd:0d17:76f7:3e82::/64"));
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:0000:0000:0000:0000"), "fddd:0d17:76f7:3e82::/64"));
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:1111:1234:5678:abcd"), "fddd:0d17:76f7:3e82::/64"));
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:ffff:ffff:ffff:ffff"), "fddd:0d17:76f7:3e82::/64"));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e83:0000:0000:0000:0000"), "fddd:0d17:76f7:3e82::/64"));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e83:ffff:ffff:ffff:ffff"), "fddd:0d17:76f7:3e82::/64"));

Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fcdd:0d17:76f7:3e82:0000:0000:0000:0000"), "fd00::/8"));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fcdd:0d17:76f7:3e82:ffff:ffff:ffff:ffff"), "fd00::/8"));
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:0000:0000:0000:0000"), "fd00::/8"));
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:1111:755f:ffff:0d17"), "fd00::/8"));
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:ffff:ffff:ffff:ffff"), "fd00::/8"));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fedd:0d17:76f7:3e82:0000:0000:0000:0000"), "fd00::/8"));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fedd:0d17:76f7:3e82:ffff:ffff:ffff:ffff"), "fd00::/8"));
}

@Test
public void testIsInRangeSingleAddressIPv4() throws Exception {
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("192.168.1.0"), "192.168.1.0"));
for (int i = 1; i < 256; i++) {
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("192.168.1." + i), "192.168.1." + i));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("192.168.1." + i), "192.168.1.0"));
}
}

@Test
public void testIsInRangeSingleAddressIPv6() throws Exception {
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:0000:0000:ffff:ffff"),
"fddd:0d17:76f7:3e82:0000:0000:ffff:ffff"));
Assert.assertTrue(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:76f7:3e82:1234:5678:abcd:efff"),
"fddd:0d17:76f7:3e82:1234:5678:abcd:efff"));
Assert.assertFalse(NetUtil.isAddressInRange(
InetAddress.getByName("fddd:0d17:0000:3e82:0000:0000:ffff:ffff"),
"fddd:0d17:76f7:3e82:0000:0000:ffff:0000"));
}
}
69 changes: 69 additions & 0 deletions common/src/java/com/zimbra/common/account/ZAttrProvisioning.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,38 @@ public static BackupBlobsCompressType fromString(String s) throws ServiceExcepti
public boolean isNoZip() { return this == noZip;}
}

public static enum BackupDedupeCompressionType {
zstd("zstd"),
nocompression("nocompression");
private String mValue;
private BackupDedupeCompressionType(String value) { mValue = value; }
public String toString() { return mValue; }
public static BackupDedupeCompressionType fromString(String s) throws ServiceException {
for (BackupDedupeCompressionType value : values()) {
if (value.mValue.equals(s)) return value;
}
throw ServiceException.INVALID_REQUEST("invalid value: "+s+", valid values: "+ Arrays.asList(values()), null);
}
public boolean isZstd() { return this == zstd;}
public boolean isNocompression() { return this == nocompression;}
}

public static enum BackupDeduplication {
dedupe("dedupe"),
nodedupe("nodedupe");
private String mValue;
private BackupDeduplication(String value) { mValue = value; }
public String toString() { return mValue; }
public static BackupDeduplication fromString(String s) throws ServiceException {
for (BackupDeduplication value : values()) {
if (value.mValue.equals(s)) return value;
}
throw ServiceException.INVALID_REQUEST("invalid value: "+s+", valid values: "+ Arrays.asList(values()), null);
}
public boolean isDedupe() { return this == dedupe;}
public boolean isNodedupe() { return this == nodedupe;}
}

public static enum BackupMode {
Standard("Standard"),
Auto_Grouped("Auto-Grouped");
Expand Down Expand Up @@ -4069,6 +4101,43 @@ public static TwoFactorAuthSecretEncoding fromString(String s) throws ServiceExc
@ZAttr(id=4018)
public static final String A_zimbraBackupCrontabConfig = "zimbraBackupCrontabConfig";

/**
* Flag to enable or disable the cross session deduplication
*
* @since ZCS 10.1.16
*/
@ZAttr(id=4149)
public static final String A_zimbraBackupCrossSessionDedupeEnabled = "zimbraBackupCrossSessionDedupeEnabled";

/**
* Attribute to check whether we need to reset the CSD backup if there
*
* @since ZCS 10.1.16
*/
@ZAttr(id=4150)
public static final String A_zimbraBackupCSDReset = "zimbraBackupCSDReset";

/**
* Blobs inside a dedupe backup are compressed by default in zstd format.
* zstd - blobs are backed up with Zstandard compression (default).
* nocompression - blobs are backed up as individual files without
* compression.
*
* @since ZCS 10.1.16
*/
@ZAttr(id=4148)
public static final String A_zimbraBackupDedupeCompressionType = "zimbraBackupDedupeCompressionType";

/**
* Blob Deduplication enabled during Backup dedupe - blobs deduplication
* is enabled during the backup (default). nodedupe - blobs deduplication
* is disabled during the backup.
*
* @since ZCS 10.1.16
*/
@ZAttr(id=4147)
public static final String A_zimbraBackupDeduplication = "zimbraBackupDeduplication";

/**
* Whether or not account is eligible for backup If true on cos level
* then backup accounts for cos. zimbraDomainDefaultCOSId is considered.
Expand Down
2 changes: 2 additions & 0 deletions common/src/java/com/zimbra/common/localconfig/LC.java
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,8 @@ public enum PUBLIC_SHARE_VISIBILITY { samePrimaryDomain, all, none };
@Supported
public static final KnownKey zimbra_license_election_leader_zimbraId = KnownKey.newKey("");

// Comma-delimited list of CIDR subnets or IP to which we always allow redirects.
public static final KnownKey zimbra_proxy_servlet_whitelist = KnownKey.newKey("");

static {
// Automatically set the key name with the variable name.
Expand Down
7 changes: 7 additions & 0 deletions common/src/java/com/zimbra/common/soap/BackupConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,14 @@ public final class BackupConstants {
public static final String A_SYNC = "sync";
public static final String A_NG_MIGRATION = "ngMigration";
public static final String A_ZIP = "zip";
public static final String A_NO_ZIP = "noZip";
public static final String A_ZIP_STORE = "zipStore";
public static final String A_ZSTD = "zstd";
public static final String A_DEDUPE = "dedupe";
public static final String A_NO_DEDUPE = "nodedupe";
public static final String A_CSD = "csd";
public static final String A_NO_CSD = "noCsd";
public static final String A_CSD_COMMON = "csdc";
public static final String A_SERVER = "server";
public static final String A_STATUS = "status";
public static final String A_REPLAY_CURRENT_REDOLOGS = "replayRedo";
Expand Down
70 changes: 70 additions & 0 deletions common/src/java/com/zimbra/common/util/NetUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.nio.channels.ServerSocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -212,5 +213,74 @@ public static void main(String[] args) {
System.out.println(c);
}

/**
* Determines if a target address falls within the specified subnet.<br>
* If the prefix has no bit-length, determines direct match with target address.
* @param targetAddress The address in question
* @param prefix CIDR notation (first ip and number of relevant bits), or single ip - no wildcards
* @return True if the address matches or is within subnet range
*/
public static boolean isAddressInRange(InetAddress targetAddress, String prefix) {
ZimbraLog.misc.debug("checking if ip: %s is in range of: %s", targetAddress, prefix);
// split first ip from bit length
String [] firstIpAndLength = prefix.split("/");
// the first ip in the subnet
InetAddress firstIp;
// the number of relevant bits in the entire address
int bitLength;
try {
firstIp = InetAddress.getByName(firstIpAndLength[0]);
// compare direct if no bit length
if (firstIpAndLength.length < 2) {
return targetAddress.getHostAddress().equals(firstIp.getHostAddress());
}
bitLength = Integer.parseInt(firstIpAndLength[1]);
} catch (UnknownHostException | NumberFormatException e) {
ZimbraLog.misc.error("ignoring unparsable ip address prefix: %s", prefix);
ZimbraLog.misc.debug(e);
return false;
}

// don't compare across ipv4 vs ipv6
if (!targetAddress.getClass().equals(firstIp.getClass())) {
ZimbraLog.misc.debug("cannot compare across ipv4 and ipv6 address. target: %s, first ip: %s",
targetAddress, firstIp);
return false;
}

// determine number of relevant bytes to compare
// e.g. /116 -> 116/8=14.5 -> 14 -> remaining bits handled below
// e.g. /30 -> 30/8=3.75 -> 4 -> remaining bits handled below
// e.g. /24 -> 24/8=3 -> 3
int maskLength = bitLength / Byte.SIZE;

// mask on and compare #maskLength bytes we care about
byte mask = (byte) 0xFF;
byte [] targetBytes = targetAddress.getAddress();
byte [] subBytes = firstIp.getAddress();
for (int i = 0; i < maskLength; i++) {
if ((targetBytes[i] & mask) != (subBytes[i] & mask)) {
return false;
}
}

// the number of relevant bits in the last byte of the address
int doCareLength = bitLength % Byte.SIZE;

// last byte is only relevant for non-multiples of 8
// last byte has all bits on except the don't cares specified by bit length
// e.g. /30 -> 30%8=6 -> 8-6=2 -> last 2 bits are off
// e.g. /29 -> 29%8=5 -> 8-5=3 -> last 3 bits are off
if (doCareLength != 0) {
// set on all bits
byte lastByteMask = (byte) 0xFF;
// set off the lowest bits remaining from a full byte
int dontCareLength = Byte.SIZE - doCareLength;
lastByteMask <<= dontCareLength;
return (targetBytes[maskLength] & lastByteMask) == (subBytes[maskLength] & lastByteMask);
}

return true;
}

}
3 changes: 1 addition & 2 deletions common/src/java/com/zimbra/common/util/Props2Js.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ private static void printEscaped(DataOutputStream out, String s)
} // printEscaped(PrintStream,String)

public static String getCommentSafeString(String st) {
return st.replaceAll("<", "") //make sure you can't start a "script" tag within the comment cuz genius IE supposedly exectutes it
.replaceAll("\n", ""); //make sure no newline can be injected to start a malicious script too
return st.replaceAll("[^A-Za-z0-9_\\-./]", "");
}

public static void main(String[] argv) throws Exception {
Expand Down
33 changes: 33 additions & 0 deletions soap/src/java/com/zimbra/soap/mail/type/CalendarItemInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,39 @@ public Invitation getInviteFromId(int id) {
}
return null;
}

/**
* Returns the Invitation with matching RECURRENCE-ID date/time, expressed as
* "YYYYMMDD[ThhmmssZ]" string. If time comonent is specified, it must be
* in UTC timezone ("Z").
* If no matching one is found, the default/series Invite is returned.
* @param recurIdZ
* @return Invitation
*/

public Invitation getInviteForRecurIdZ(String recurIdZ) {
Invitation defInv = null;
for (Invitation inv : invites) {
String rid = inv.getRecurrenceId();
if (recurIdZ != null) {
if (rid == null) {
if (defInv == null) {
defInv = inv;
}
} else {
if (recurIdZ.equals(rid)) {
return inv;
}
}
} else { // recurIdZ == null
if (rid == null) {
return inv;
}
}
}
return defInv;
}

public List<CalendarReply> getCalendarReplies() {
return Collections.unmodifiableList(calendarReplies);
}
Expand Down
Loading